Skip to content

Commit

Permalink
Fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
brianquinlan committed Oct 4, 2024
1 parent 254577d commit 93d688a
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ class ObjCBuiltInFunctions {
'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 @@ -128,8 +132,9 @@ class ObjCBuiltInFunctions {
generateForPackageObjectiveC ? null : builtInCompounds[name];
bool isBuiltInEnum(String name) =>
!generateForPackageObjectiveC && builtInEnums.contains(name);
bool isBuiltInProtocol(String name) =>
!generateForPackageObjectiveC && builtInProtocols.contains(name);
bool isNSObject(String name) => name == 'NSObject';

// We need to load a separate instance of objc_msgSend for each signature. If
// the return type is a struct, we need to use objc_msgSend_stret instead, and
// for float return types we need objc_msgSend_fpret.
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
3 changes: 3 additions & 0 deletions pkgs/objective_c/ffigen_objc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ objc-interfaces:
- NSURLHandle
- NSValue
- Protocol
objc-protocols:
include:
- NSStreamDelegate
structs:
include:
- _NSRange
Expand Down
1 change: 1 addition & 0 deletions pkgs/objective_c/lib/objective_c.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export 'src/objective_c_bindings_generated.dart'
NSSet,
NSSortOptions,
NSStream,
NSStreamDelegate,
NSStreamEvent,
NSStreamStatus,
NSString,
Expand Down
62 changes: 62 additions & 0 deletions pkgs/objective_c/lib/src/objective_c_bindings_generated.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8314,6 +8314,67 @@ class NSStream extends NSObject {
}
}

/// NSStreamDelegate
abstract final class NSStreamDelegate {
/// Builds an object that implements the NSStreamDelegate protocol. To implement
/// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly.
static objc.ObjCObjectBase implement(
{void Function(NSStream, NSStreamEvent)? stream_handleEvent_}) {
final builder = objc.ObjCProtocolBuilder();
NSStreamDelegate.stream_handleEvent_
.implement(builder, stream_handleEvent_);
return builder.build();
}

/// Adds the implementation of the NSStreamDelegate protocol to an existing
/// [objc.ObjCProtocolBuilder].
static void addToBuilder(objc.ObjCProtocolBuilder builder,
{void Function(NSStream, NSStreamEvent)? stream_handleEvent_}) {
NSStreamDelegate.stream_handleEvent_
.implement(builder, stream_handleEvent_);
}

/// Builds an object that implements the NSStreamDelegate protocol. To implement
/// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. All
/// methods that can be implemented as listeners will be.
static objc.ObjCObjectBase implementAsListener(
{void Function(NSStream, NSStreamEvent)? stream_handleEvent_}) {
final builder = objc.ObjCProtocolBuilder();
NSStreamDelegate.stream_handleEvent_
.implementAsListener(builder, stream_handleEvent_);
return builder.build();
}

/// Adds the implementation of the NSStreamDelegate protocol to an existing
/// [objc.ObjCProtocolBuilder]. All methods that can be implemented as listeners will
/// be.
static void addToBuilderAsListener(objc.ObjCProtocolBuilder builder,
{void Function(NSStream, NSStreamEvent)? stream_handleEvent_}) {
NSStreamDelegate.stream_handleEvent_
.implementAsListener(builder, stream_handleEvent_);
}

/// stream:handleEvent:
static final stream_handleEvent_ =
objc.ObjCProtocolListenableMethod<void Function(NSStream, NSStreamEvent)>(
_sel_stream_handleEvent_,
objc.getProtocolMethodSignature(
_protocol_NSStreamDelegate,
_sel_stream_handleEvent_,
isRequired: false,
isInstanceMethod: true,
),
(void Function(NSStream, NSStreamEvent) func) =>
ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent.fromFunction(
(ffi.Pointer<ffi.Void> _, NSStream arg1, NSStreamEvent arg2) =>
func(arg1, arg2)),
(void Function(NSStream, NSStreamEvent) func) =>
ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent.listener(
(ffi.Pointer<ffi.Void> _, NSStream arg1, NSStreamEvent arg2) =>
func(arg1, arg2)),
);
}

enum NSStreamEvent {
NSStreamEventNone(0),
NSStreamEventOpenCompleted(1),
Expand Down Expand Up @@ -15498,6 +15559,7 @@ final _objc_msgSend_z1lin0 = objc.msgSendPointer
.asFunction<
bool Function(ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>, ffi.Pointer<ffi.Char>, int)>();
late final _protocol_NSStreamDelegate = objc.getProtocol("NSStreamDelegate");
late final _sel_URLByAppendingPathComponent_ =
objc.registerName("URLByAppendingPathComponent:");
late final _sel_URLByAppendingPathComponent_isDirectory_ =
Expand Down
3 changes: 1 addition & 2 deletions pkgs/objective_c/src/input_stream_adapter.m
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,7 @@ - (BOOL)hasBytesAvailable {
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
id<NSStreamDelegate> delegate = _delegate;
if (delegate != self) {
os_log_with_type(OS_LOG_DEFAULT, OS_LOG_TYPE_ERROR,
"DartInputStreamAdapter: non-self delegate was invoked");
[delegate stream:self handleEvent:streamEvent];
}
}

Expand Down
31 changes: 31 additions & 0 deletions pkgs/objective_c/test/interface_lists_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ void main() {
late List<String> yamlInterfaces;
late List<String> yamlStructs;
late List<String> yamlEnums;
late List<String> yamlProtocols;

setUpAll(() {
final yaml =
Expand All @@ -38,6 +39,11 @@ void main() {
.map<String>((dynamic i) => i as String)
.toList()
..sort();
yamlProtocols = ((yaml['objc-protocols'] as YamlMap)['include']
as YamlList)
.map<String>((dynamic i) => i as String)
.toList()
..sort();
});

test('ObjCBuiltInFunctions.builtInInterfaces', () {
Expand All @@ -52,6 +58,10 @@ void main() {
expect(ObjCBuiltInFunctions.builtInEnums, yamlEnums);
});

test('ObjCBuiltInFunctions.builtInProtocols', () {
expect(ObjCBuiltInFunctions.builtInProtocols, yamlProtocols);
});

test('package:objective_c exports all the interfaces', () {
final exportFile = File('lib/objective_c.dart').readAsStringSync();
for (final intf in yamlInterfaces) {
Expand All @@ -75,6 +85,13 @@ void main() {
}
});

test('package:objective_c exports all the protocols', () {
final exportFile = File('lib/objective_c.dart').readAsStringSync();
for (final protocol in yamlProtocols) {
expect(exportFile, contains(protocol));
}
});

test('All code genned interfaces are included in the list', () {
final classNameRegExp = RegExp(r'^class (\w+) ');
final allClassNames = <String>[];
Expand Down Expand Up @@ -119,5 +136,19 @@ void main() {
}
expect(allEnumNames, unorderedEquals(yamlEnums));
});

test('All code genned protocols are included in the list', () {
final protocolNameRegExp =
RegExp(r'^abstract final class (?!ObjCBlock_)(\w+) {');
final allProtocolNames = <String>[];
for (final line in File('lib/src/objective_c_bindings_generated.dart')
.readAsLinesSync()) {
final match = protocolNameRegExp.firstMatch(line);
if (match != null) {
allProtocolNames.add(match[1]!);
}
}
expect(allProtocolNames, unorderedEquals(yamlProtocols));
});
});
}
24 changes: 15 additions & 9 deletions pkgs/objective_c/test/ns_input_stream_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'dart:typed_data';

import 'package:ffi/ffi.dart';
import 'package:objective_c/objective_c.dart';
import 'package:objective_c/src/objective_c_bindings_generated.dart';
import 'package:test/test.dart';

Future<(int, Uint8List, bool, NSStreamStatus, NSError?)> read(
Expand Down Expand Up @@ -244,25 +245,30 @@ void main() {
});

group('delegate', () {
late NSInputStream inputStream;
late DartInputStreamAdapter inputStream;

setUp(() {
inputStream = Stream.fromIterable([
[1, 2, 3],
]).toNSInputStream();
]).toNSInputStream() as DartInputStreamAdapter;
});

test('default delegate', () async {
expect(inputStream.delegate, inputStream);
inputStream.stream_handleEvent_(
inputStream, NSStreamEvent.NSStreamEventOpenCompleted);
});

test('assign to non-self', () async {
inputStream.delegate = [1, 2, 3].toNSData();
inputStream.open();
final (count, data, hasBytesAvailable, status, error) =
await read(inputStream, 3);
expect(count, 3);
expect(error, null);
test('non-self delegate', () async {
final protoBuilder = ObjCProtocolBuilder();
final events = <NSStreamEvent>[];

NSStreamDelegate.addToBuilder(protoBuilder,
stream_handleEvent_: (stream, event) => events.add(event));
inputStream.delegate = protoBuilder.build();
inputStream.stream_handleEvent_(
inputStream, NSStreamEvent.NSStreamEventOpenCompleted);
expect(events, [NSStreamEvent.NSStreamEventOpenCompleted]);
});

test('assign to null', () async {
Expand Down

0 comments on commit 93d688a

Please sign in to comment.