Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a converter from Dart Stream to NSInputStream #1555

Open
wants to merge 43 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
8922f87
Add a converter from Dart `Stream` to `NSInputStream`
brianquinlan Sep 13, 2024
af7f981
Clarify the deadlock behavior of `toNSInputStream`.
brianquinlan Sep 13, 2024
903a7de
Update ns_input_stream_test.dart
brianquinlan Sep 13, 2024
c8215be
Update ns_input_stream_test.dart
brianquinlan Sep 13, 2024
55788d7
Update input_stream_adapter.m
brianquinlan Sep 26, 2024
6c6383d
Merge remote-tracking branch 'upstream/main' into stream
brianquinlan Sep 26, 2024
893d1ff
Update CHANGELOG.md
brianquinlan Sep 26, 2024
3ac018f
Merge remote-tracking branch 'upstream/main' into stream
brianquinlan Sep 27, 2024
041c969
More work
brianquinlan Sep 27, 2024
5893796
Fix
brianquinlan Sep 27, 2024
78f8bba
Fixes
brianquinlan Sep 27, 2024
d40f878
Update objective_c.yaml
brianquinlan Sep 27, 2024
a0b5769
Update ns_input_stream.dart
brianquinlan Sep 27, 2024
c7c5c35
Update ns_input_stream.dart
brianquinlan Sep 27, 2024
a02e729
Update ns_input_stream.dart
brianquinlan Sep 27, 2024
a34f3c8
Update ns_input_stream.dart
brianquinlan Sep 27, 2024
f9abb11
Update ns_input_stream.dart
brianquinlan Sep 27, 2024
3147c62
Update ns_input_stream_test.dart
brianquinlan Sep 27, 2024
51ad42b
Update ns_input_stream_test.dart
brianquinlan Sep 27, 2024
2f145e8
More tries
brianquinlan Sep 28, 2024
b3965ff
Update ns_input_stream.dart
brianquinlan Sep 28, 2024
0f683a4
Update ns_input_stream_test.dart
brianquinlan Sep 28, 2024
7bc0624
Update ns_input_stream_test.dart
brianquinlan Sep 28, 2024
365f095
Update ns_input_stream_test.dart
brianquinlan Sep 28, 2024
67d6f18
Update ns_input_stream_test.dart
brianquinlan Sep 30, 2024
f725e2a
Merge remote-tracking branch 'upstream/main' into stream
brianquinlan Sep 30, 2024
508b840
Update objective_c_bindings_generated.dart
brianquinlan Sep 30, 2024
4cef393
Merge branch 'main' into stream
brianquinlan Sep 30, 2024
f4a5b74
Fix
brianquinlan Sep 30, 2024
fae63ae
Update pubspec.yaml
brianquinlan Sep 30, 2024
4a5cf95
Fixes
brianquinlan Sep 30, 2024
16b38ad
Update ns_input_stream_test.dart
brianquinlan Sep 30, 2024
5b35857
Update input_stream_adapter.h
brianquinlan Sep 30, 2024
c9e17ad
Regenerate
brianquinlan Sep 30, 2024
c67c4b8
Add comment
brianquinlan Oct 1, 2024
1c1a3c8
Update input_stream_adapter.m
brianquinlan Oct 1, 2024
c4e42a1
Update input_stream_adapter.m
brianquinlan Oct 1, 2024
442af62
Update input_stream_adapter.m
brianquinlan Oct 1, 2024
d0f65b6
Update interface_lists_test.dart
brianquinlan Oct 1, 2024
254577d
Update ns_input_stream_test.dart
brianquinlan Oct 2, 2024
93d688a
Fixes
brianquinlan Oct 4, 2024
8069f02
Update CHANGELOG.md
brianquinlan Oct 4, 2024
5941854
Merge remote-tracking branch 'upstream/main' into stream
brianquinlan Oct 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkgs/ffigen/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- Bump minimum Dart version to 3.4.
- Dedupe `ObjCBlock` trampolines to reduce generated ObjC code.
- Update to latest `package:objective_c`.
- ObjC objects now include the methods from the protocols they implement. Both
required and optional methods are included. Optional methods will throw an
exception if the method isn't implemented.
Expand Down
14 changes: 14 additions & 0 deletions pkgs/ffigen/lib/src/code_generator/objc_built_in_functions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ class ObjCBuiltInFunctions {
ObjCImport('UnimplementedOptionalMethodException');

// Keep in sync with pkgs/objective_c/ffigen_objc.yaml.

@visibleForTesting
static const builtInInterfaces = {
'DartInputStreamAdapter',
'DartProxy',
'DartProxyBuilder',
'NSArray',
Expand All @@ -58,6 +60,7 @@ class ObjCBuiltInFunctions {
'NSEnumerator',
'NSError',
'NSIndexSet',
'NSInputStream',
'NSInvocation',
'NSItemProvider',
'NSLocale',
Expand All @@ -73,8 +76,11 @@ class ObjCBuiltInFunctions {
'NSNumber',
'NSObject',
'NSOrderedSet',
'NSOutputStream',
'NSProxy',
'NSRunLoop',
'NSSet',
'NSStream',
'NSString',
'NSURL',
'NSURLHandle',
Expand Down Expand Up @@ -104,13 +110,19 @@ class ObjCBuiltInFunctions {
'NSKeyValueSetMutationKind',
'NSOrderedCollectionDifferenceCalculationOptions',
'NSSortOptions',
'NSStreamEvent',
'NSStreamStatus',
'NSStringCompareOptions',
'NSStringEncodingConversionOptions',
'NSStringEnumerationOptions',
'NSURLBookmarkCreationOptions',
'NSURLBookmarkResolutionOptions',
'NSURLHandleStatus',
};
@visibleForTesting
static const builtInProtocols = {
'NSStreamDelegate',
};

// TODO(https://github.com/dart-lang/native/issues/1173): Ideally this check
// would be based on more than just the name.
Expand All @@ -120,6 +132,8 @@ class ObjCBuiltInFunctions {
generateForPackageObjectiveC ? null : builtInCompounds[name];
bool isBuiltInEnum(String name) =>
!generateForPackageObjectiveC && builtInEnums.contains(name);
bool isBuiltInProtocol(String name) =>
!generateForPackageObjectiveC && builtInProtocols.contains(name);
static bool isNSObject(String name) => name == 'NSObject';

// We need to load a separate instance of objc_msgSend for each signature. If
Expand Down
3 changes: 2 additions & 1 deletion pkgs/ffigen/lib/src/code_generator/objc_protocol.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ class ObjCProtocol extends NoLookUpBinding with ObjCMethods {

@override
void sort() => sortMethods();
bool get _isBuiltIn => builtInFunctions.isBuiltInProtocol(originalName);

@override
BindingString toBindingString(Writer w) {
if (!generateBindings) {
if (!generateBindings || _isBuiltIn) {
return const BindingString(
type: BindingStringType.objcProtocol, string: '');
}
Expand Down
2 changes: 1 addition & 1 deletion pkgs/ffigen/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ dev_dependencies:
dart_flutter_team_lints: ^2.0.0
json_schema: ^5.1.1
leak_tracker: ^10.0.7
objective_c: ^2.1.0
objective_c: ^3.0.0
test: ^1.16.2

dependency_overrides:
Expand Down
12 changes: 10 additions & 2 deletions pkgs/objective_c/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
## 2.1.0-wip

## 3.0.0-wip

- Add the following stream-related types to the core package:
- `NSInputStream`
- `NSOutputStream`
- `NSRunLoop`
- `NSStream`
- `NSStreamDelegate`
- `NSStreamEvent`
- `NSStreamStatus`
- Add `UnimplementedOptionalMethodException`, which is thrown by the ObjC
bindings if an optional method is invoked, and the instance doesn't implement
the method.
Expand Down
14 changes: 14 additions & 0 deletions pkgs/objective_c/ffigen_objc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ output:
headers:
entry-points:
- 'src/foundation.h'
- 'src/input_stream_adapter.h'
- 'src/proxy.h'
ffi-native:
exclude-all-by-default: true
Expand All @@ -22,6 +23,7 @@ external-versions:
objc-interfaces:
# Keep in sync with ffigen's ObjCBuiltInFunctions.builtInInterfaces.
include:
- DartInputStreamAdapter
- DartProxy
- DartProxyBuilder
- NSArray
Expand All @@ -33,6 +35,7 @@ objc-interfaces:
- NSEnumerator
- NSError
- NSIndexSet
- NSInputStream
- NSInvocation
- NSItemProvider
- NSLocale
Expand All @@ -47,14 +50,20 @@ objc-interfaces:
- NSNotification
- NSNumber
- NSObject
- NSOutputStream
- NSOrderedSet
- NSProxy
- NSRunLoop
- NSSet
- NSStream
- NSString
- NSURL
- NSURLHandle
- NSValue
- Protocol
objc-protocols:
include:
- NSStreamDelegate
structs:
include:
- _NSRange
Expand All @@ -79,12 +88,17 @@ enums:
- NSKeyValueSetMutationKind
- NSOrderedCollectionDifferenceCalculationOptions
- NSSortOptions
- NSStreamEvent
- NSStreamStatus
- NSStringCompareOptions
- NSStringEncodingConversionOptions
- NSStringEnumerationOptions
- NSURLBookmarkCreationOptions
- NSURLBookmarkResolutionOptions
- NSURLHandleStatus
globals:
include:
- NSLocalizedDescriptionKey
preamble: |
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
Expand Down
1 change: 1 addition & 0 deletions pkgs/objective_c/ios/Classes/objective_c.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

// Relative import to be able to reuse the ObjC sources.
// See the comment in ../objective_c.podspec for more information.
#include "../../src/input_stream_adapter.m"
#include "../../src/objective_c.m"
#include "../../src/objective_c_bindings_generated.m"
#include "../../src/proxy.m"
8 changes: 8 additions & 0 deletions pkgs/objective_c/lib/objective_c.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export 'src/internal.dart'
isValidClass,
isValidObject;
export 'src/ns_data.dart';
export 'src/ns_input_stream.dart';
export 'src/ns_mutable_data.dart';
export 'src/ns_string.dart';
// Keep in sync with pkgs/objective_c/ffigen_objc.yaml.
Expand All @@ -45,6 +46,7 @@ export 'src/objective_c_bindings_generated.dart'
NSError,
NSFastEnumerationState,
NSIndexSet,
NSInputStream,
NSInvocation,
NSItemProvider,
NSItemProviderFileOptions,
Expand All @@ -66,10 +68,16 @@ export 'src/objective_c_bindings_generated.dart'
NSObject,
NSOrderedCollectionDifferenceCalculationOptions,
NSOrderedSet,
NSOutputStream,
NSProxy,
NSRange,
NSRunLoop,
NSSet,
NSSortOptions,
NSStream,
NSStreamDelegate,
NSStreamEvent,
NSStreamStatus,
NSString,
NSStringCompareOptions,
NSStringEncodingConversionOptions,
Expand Down
57 changes: 57 additions & 0 deletions pkgs/objective_c/lib/src/ns_input_stream.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import 'dart:async';
import 'dart:ffi';
import 'dart:isolate';

import 'ns_data.dart';
import 'ns_string.dart';
import 'objective_c_bindings_generated.dart';

extension NSInputStreamStreamExtension on Stream<List<int>> {
/// Return a [NSInputStream] that, when read, will contain the contents of
/// the [Stream].
///
/// > [!IMPORTANT]
/// > [NSInputStream.read_maxLength_] must be called from a different thread
/// > or [Isolate] than the one that calls [toNSInputStream]. Otherwise,
/// > [NSInputStream.read_maxLength_] will deadlock waiting for data to be
/// > added from the [Stream].
NSInputStream toNSInputStream() {
// Eagerly add data until `maxReadAheadSize` is buffered.
const maxReadAheadSize = 4096;

final port = ReceivePort();
final inputStream =
DartInputStreamAdapter.inputStreamWithPort_(port.sendPort.nativePort);
late final StreamSubscription<dynamic> dataSubscription;

dataSubscription = listen((data) {
if (inputStream.addData_(data.toNSData()) > maxReadAheadSize) {
dataSubscription.pause();
}
}, onError: (Object e) {
final d = NSMutableDictionary.new1();
d.setObject_forKey_(e.toString().toNSString(), NSLocalizedDescriptionKey);
inputStream.setError_(NSError.errorWithDomain_code_userInfo_(
'DartError'.toNSString(), 0, d));
port.close();
}, onDone: () {
inputStream.setDone();
port.close();
}, cancelOnError: true);

dataSubscription.pause();
port.listen((count) {
// -1 indicates that the `NSInputStream` is closed. All other values
// indicate that the `NSInputStream` needs more data.
if (count == -1) {
dataSubscription.cancel();
} else {
dataSubscription.resume();
}
}, onDone: () {
dataSubscription.cancel();
});

return inputStream;
}
}
Loading
Loading