Skip to content
Closed

ignore #10232

Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
eb7cac6
methods, basic types, sync, nullable-sync, async, and classes
tarrinneal Apr 15, 2025
9fa695d
broken nullable async methods
tarrinneal Apr 15, 2025
0aff0fd
refactor type logic, add codec
tarrinneal Apr 17, 2025
1ed8a8b
objects and enums
tarrinneal Apr 22, 2025
ee50607
full codec
tarrinneal May 9, 2025
4c6eb1a
error handling and more tests
tarrinneal May 29, 2025
f87efd4
fix codec
tarrinneal May 29, 2025
3e9d9f0
flutter api and plumbing through legacy apis and tests
tarrinneal Jun 27, 2025
6ad2e37
jnigen.yaml
tarrinneal Jun 27, 2025
9b55d44
ffi just getting started
tarrinneal Jul 7, 2025
25e8c30
gen fluff
tarrinneal Jul 11, 2025
df40332
not working
tarrinneal Jul 16, 2025
d90ecca
missing files
tarrinneal Jul 17, 2025
92933f8
gitignore
tarrinneal Jul 17, 2025
cb1c0fe
ios ffigen settings
tarrinneal Jul 17, 2025
a7cc7ce
remove macos min version from ffigen config
tarrinneal Jul 17, 2025
8fb8dca
no dylibs
tarrinneal Jul 17, 2025
ab64302
more basic, still can't see class
tarrinneal Jul 17, 2025
c7d00c6
upload macos
tarrinneal Jul 17, 2025
33f8fa1
fix ffigen files
tarrinneal Jul 17, 2025
4977cc2
test
tarrinneal Jul 29, 2025
586edf2
wip
tarrinneal Jul 29, 2025
74b1cb1
Merge branch 'Frillback' of github.com:tarrinneal/packages into Frill…
tarrinneal Jul 29, 2025
3736528
ns
tarrinneal Jul 29, 2025
31d182f
dunno
tarrinneal Jul 30, 2025
c63e598
something
tarrinneal Jul 30, 2025
6dc23e7
working again
tarrinneal Jul 30, 2025
982dfe6
Merge branch 'Frillback' of https://github.com/tarrinneal/packages in…
tarrinneal Jul 30, 2025
ecc088a
enums
tarrinneal Aug 12, 2025
927fd8d
and this one
tarrinneal Aug 12, 2025
877d60d
ffi support for classes, enums, and objects (partial testing)
tarrinneal Aug 26, 2025
910ac95
tests
tarrinneal Aug 26, 2025
b522d6c
fix enums, still need to resolve Any?
tarrinneal Sep 4, 2025
bd47b34
actually fix enums
tarrinneal Sep 5, 2025
4192a89
starting nullables, gonna be a mess
tarrinneal Sep 5, 2025
86e6907
nullable base types in classes
tarrinneal Sep 17, 2025
87f4f8a
add nullable enums (no tests for null things though.....)
tarrinneal Sep 18, 2025
ed3eb93
update to latest version
tarrinneal Sep 19, 2025
457edef
Not even I understand
tarrinneal Sep 24, 2025
9214479
fix null object?
tarrinneal Sep 25, 2025
aadd859
multi-arity and nullable enums in classes
tarrinneal Sep 26, 2025
8cb24b6
nested classes
tarrinneal Sep 27, 2025
d29e86a
typed lists and maps except int keys
tarrinneal Oct 14, 2025
b32d506
Merge branch 'main' of https://github.com/flutter/packages into Frill…
tarrinneal Oct 15, 2025
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
Prev Previous commit
Next Next commit
nested classes
  • Loading branch information
tarrinneal committed Sep 27, 2025
commit 8cb24b66de8dd32b349094d3b93bd8a610206253
79 changes: 39 additions & 40 deletions packages/pigeon/lib/src/dart/dart_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,6 @@ class _FfiType {
return _wrapInNullCheckIfNullable(
nullable: type.isNullable,
varName: name,
ifNull: '${ffiType.ffiName}.alloc()',
code:
'$name${_getForceNonNullSymbol(type.isNullable && forceNonNull)}.toFfi()',
);
Expand Down Expand Up @@ -1027,19 +1026,19 @@ class DartGenerator extends StructuredGenerator<InternalDartOptions> {
}

void _writeToJni(Indent indent, Class classDefinition) {
indent.writeScoped('jni_bridge.${classDefinition.name} toJni() {', '}', () {
indent.writeScoped('return jni_bridge.${classDefinition.name} (', ');',
() {
for (final NamedType field in getFieldsInSerializationOrder(
classDefinition,
)) {
final _JniType jniType = _JniType.fromTypeDeclaration(field.type);
indent.writeln(
'${field.name}: ${jniType.getToJniCall(field.type, field.name, jniType, forceNonNull: true)},',
);
}
});
});
// indent.writeScoped('jni_bridge.${classDefinition.name} toJni() {', '}', () {
// indent.writeScoped('return jni_bridge.${classDefinition.name} (', ');',
// () {
// for (final NamedType field in getFieldsInSerializationOrder(
// classDefinition,
// )) {
// final _JniType jniType = _JniType.fromTypeDeclaration(field.type);
// indent.writeln(
// '${field.name}: ${jniType.getToJniCall(field.type, field.name, jniType, forceNonNull: true)},',
// );
// }
// });
// });
}

void _writeToFfi(Indent indent, Class classDefinition) {
Expand Down Expand Up @@ -1070,27 +1069,27 @@ class DartGenerator extends StructuredGenerator<InternalDartOptions> {
}

void _writeFromJni(Indent indent, Class classDefinition) {
final _JniType jniClass = _JniType.fromClass(classDefinition);
indent.writeScoped(
'static ${jniClass.type.baseName}? fromJni(${jniClass.jniName}? jniClass) {',
'}',
() {
indent.writeScoped(
'return jniClass == null ? null : ${jniClass.type.baseName}(',
');',
() {
for (final NamedType field in getFieldsInSerializationOrder(
classDefinition,
)) {
final _JniType jniType = _JniType.fromTypeDeclaration(field.type);
indent.writeln(
'${field.name}: ${jniType.getToDartCall(field.type, varName: 'jniClass.${jniType.getJniGetterMethodName(field.name)}')},',
);
}
},
);
},
);
// final _JniType jniClass = _JniType.fromClass(classDefinition);
// indent.writeScoped(
// 'static ${jniClass.type.baseName}? fromJni(${jniClass.jniName}? jniClass) {',
// '}',
// () {
// indent.writeScoped(
// 'return jniClass == null ? null : ${jniClass.type.baseName}(',
// ');',
// () {
// for (final NamedType field in getFieldsInSerializationOrder(
// classDefinition,
// )) {
// final _JniType jniType = _JniType.fromTypeDeclaration(field.type);
// indent.writeln(
// '${field.name}: ${jniType.getToDartCall(field.type, varName: 'jniClass.${jniType.getJniGetterMethodName(field.name)}')},',
// );
// }
// },
// );
// },
// );
}

void _writeFromFfi(Indent indent, Class classDefinition) {
Expand Down Expand Up @@ -2491,9 +2490,9 @@ class _PigeonJniCodec {
${root.classes.map((Class dataClass) {
final _JniType jniType = _JniType.fromClass(dataClass);
return '''
} else if (value.isA<${jniType.jniName}>(
${jniType.jniName}.type)) {
return ${jniType.type.baseName}.fromJni(value.as(${jniType.jniName}.type));
// } else if (value.isA<${jniType.jniName}>(
// ${jniType.jniName}.type)) {
// return ${jniType.type.baseName}.fromJni(value.as(${jniType.jniName}.type));
''';
}).join()}
${root.enums.map((Enum enumDefinition) {
Expand Down Expand Up @@ -2622,8 +2621,8 @@ class _PigeonJniCodec {
${root.classes.map((Class dataClass) {
final _JniType jniType = _JniType.fromClass(dataClass);
return '''
} else if (value is ${jniType.type.baseName}) {
return value.toJni() as T;
// } else if (value is ${jniType.type.baseName}) {
// return value.toJni() as T;
''';
}).join()}
${root.enums.map((Enum enumDefinition) {
Expand Down
76 changes: 45 additions & 31 deletions packages/pigeon/lib/src/swift/swift_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,9 @@ if (wrapped == nil) {
});
}

/////////// THESE NEED TO BE RECONCILED
// TODO

String _varToObjc(String varName, TypeDeclaration type) {
final String nullable = type.isNullable ? '?' : '';
switch (type.baseName) {
Expand All @@ -808,6 +811,9 @@ if (wrapped == nil) {
if (type.isEnum && type.isNullable) {
return _numberToObjc(varName, getter: '!.rawValue');
}
if (type.isClass) {
return '${type.baseName}Bridge.fromSwift($varName)';
}
return varName;
}
}
Expand Down Expand Up @@ -838,10 +844,48 @@ if (wrapped == nil) {
? 'isNullish($varName) ? nil : ${type.baseName}.init(rawValue: $varName!.intValue)'
: varName;
}
if (type.isClass) {
final String checkNullish =
type.isNullable ? 'isNullish($varName) ? nil : ' : '';
return '$checkNullish$varName${nullable.isEmpty ? '' : '!'}.toSwift()';
}
return varName;
}
}

String _ffiToSwiftConversion(NamedType param) {
final String nullable = param.type.isNullable ? '?' : '';
if (param.type.isEnum && param.type.isNullable) {
return 'isNullish(${param.name}) ? nil : ${param.type.baseName}(rawValue: ${param.name}!.intValue)${param.type.isNullable ? '' : '!'}';
}
if (param.type.isClass) {
final String checkNullish =
param.type.isNullable ? 'isNullish(${param.name}) ? nil : ' : '';
return '$checkNullish${param.name}$nullable.toSwift()';
}
if (param.type.baseName == 'Object') {
return ' _PigeonFfiCodec.readValue(value: ${param.name} as? NSObject, type: nil) as Any';
}
return '${param.name}${_conversionToObjcRequired(param.type) ? '$nullable.${toLowerCamelCase(_swiftTypeForBuiltinDartType(param.type)!)}Value' : ''}';
}

String _swiftToFfiConversion(TypeDeclaration type, String toConvert) {
if (type.isEnum) {
return 'NSNumber(value: $toConvert.rawValue)';
} else if (type.baseName == 'Object') {
return '_PigeonFfiCodec.writeValue(value: $toConvert, isObject: true)';
}
final String nullable = type.isNullable ? '?' : '';
if (_conversionToObjcRequired(type)) {
if (type.isClass) {
return '${type.baseName}Bridge.fromSwift($toConvert)';
}
return '$toConvert as$nullable ${_ffiTypeForBuiltinDartType(type)}';
}
return toConvert;
}
//////////

void _writeClassInit(Indent indent, List<NamedType> fields, String objc,
{bool useFfi = false}) {
indent.writeScoped('${objc}init(', ')', () {
Expand Down Expand Up @@ -3396,7 +3440,7 @@ String _swiftTypeForDartType(
}
return _swiftTypeForBuiltinDartType(type, mapKey: mapKey, useFfi: useFfi) ??
_swiftTypeForProxyApiType(type) ??
type.baseName;
(useFfi && type.isClass ? '${type.baseName}Bridge' : type.baseName);
}

String _ffiTypeForDartType(TypeDeclaration type,
Expand All @@ -3423,36 +3467,6 @@ String _nullSafeFfiTypeForDartType(TypeDeclaration type,
return '${_ffiTypeForDartType(type, collectionSubType: collectionSubType, forceNullable: forceNullable)}${(type.isNullable && type.baseName != 'Object') || forceNullable ? '?' : ''}';
}

String _ffiToSwiftConversion(NamedType param) {
final String nullable = param.type.isNullable ? '?' : '';
if (param.type.isEnum && param.type.isNullable) {
return 'isNullish(${param.name}) ? nil : ${param.type.baseName}(rawValue: ${param.name}!.intValue)${param.type.isNullable ? '' : '!'}';
}
if (param.type.isClass) {
return '${param.name}$nullable.toSwift()';
}
if (param.type.baseName == 'Object') {
return ' _PigeonFfiCodec.readValue(value: ${param.name} as? NSObject, type: nil) as Any';
}
return '${param.name}${_conversionToObjcRequired(param.type) ? '$nullable.${toLowerCamelCase(_swiftTypeForBuiltinDartType(param.type)!)}Value' : ''}';
}

String _swiftToFfiConversion(TypeDeclaration type, String toConvert) {
if (type.isEnum) {
return 'NSNumber(value: $toConvert.rawValue)';
} else if (type.baseName == 'Object') {
return '_PigeonFfiCodec.writeValue(value: $toConvert, isObject: true)';
}
final String nullable = type.isNullable ? '?' : '';
if (_conversionToObjcRequired(type)) {
if (type.isClass) {
return '${type.baseName}Bridge.fromSwift($toConvert)';
}
return '$toConvert as$nullable ${_ffiTypeForBuiltinDartType(type)}';
}
return toConvert;
}

String _getMethodSignature({
required String name,
required Iterable<Parameter> parameters,
Expand Down
52 changes: 26 additions & 26 deletions packages/pigeon/pigeons/ni_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -260,29 +260,29 @@ class NIAllNullableTypesWithoutRecursion {
// Map<int?, Map<Object?, Object?>?>? mapMap;
}

// /// A class for testing nested class handling.
// ///
// /// This is needed to test nested nullable and non-nullable classes,
// /// `NIAllNullableTypes` is non-nullable here as it is easier to instantiate
// /// than `NIAllTypes` when testing doesn't require both (ie. testing null classes).
// class NIAllClassesWrapper {
// NIAllClassesWrapper(
// this.allNullableTypes,
// this.allNullableTypesWithoutRecursion,
// this.allTypes,
// this.classList,
// this.classMap,
// this.nullableClassList,
// this.nullableClassMap,
// );
// NIAllNullableTypes allNullableTypes;
// NIAllNullableTypesWithoutRecursion? allNullableTypesWithoutRecursion;
// NIAllTypes? allTypes;
// List<NIAllTypes?> classList;
// List<NIAllNullableTypesWithoutRecursion?>? nullableClassList;
// Map<int?, NIAllTypes?> classMap;
// Map<int?, NIAllNullableTypesWithoutRecursion?>? nullableClassMap;
// }
/// A class for testing nested class handling.
///
/// This is needed to test nested nullable and non-nullable classes,
/// `NIAllNullableTypes` is non-nullable here as it is easier to instantiate
/// than `NIAllTypes` when testing doesn't require both (ie. testing null classes).
class NIAllClassesWrapper {
NIAllClassesWrapper(
// this.allNullableTypes,
this.allNullableTypesWithoutRecursion,
this.allTypes,
// this.classList,
// this.classMap,
// this.nullableClassList,
// this.nullableClassMap,
);
// NIAllNullableTypes allNullableTypes;
NIAllNullableTypesWithoutRecursion? allNullableTypesWithoutRecursion;
NIAllTypes? allTypes;
// List<NIAllTypes?> classList;
// List<NIAllNullableTypesWithoutRecursion?>? nullableClassList;
// Map<int?, NIAllTypes?> classMap;
// Map<int?, NIAllNullableTypesWithoutRecursion?>? nullableClassMap;
}

/// The core interface that each host language plugin must implement in
/// platform_test integration tests.
Expand Down Expand Up @@ -426,10 +426,10 @@ abstract class NIHostIntegrationCoreApi {
// Map<int, NIAllNullableTypes> echoNonNullClassMap(
// Map<int, NIAllNullableTypes> classMap);

// /// Returns the passed class to test nested class serialization and deserialization.
// @ObjCSelector('echoClassWrapper:')
/// Returns the passed class to test nested class serialization and deserialization.
@ObjCSelector('echoClassWrapper:')
// @SwiftFunction('echo(_:)')
// NIAllClassesWrapper echoClassWrapper(NIAllClassesWrapper wrapper);
NIAllClassesWrapper echoClassWrapper(NIAllClassesWrapper wrapper);

/// Returns the passed enum to test serialization and deserialization.
@ObjCSelector('echoEnum:')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,16 @@ class _ExampleAppState extends State<ExampleApp> {
// Make a single trivial call just to validate that everything is wired
// up.
// await api.noop();
// final NIHostIntegrationCoreApiForNativeInterop? api =
// NIHostIntegrationCoreApiForNativeInterop.getInstance();
final NIHostIntegrationCoreApiForNativeInterop? api =
NIHostIntegrationCoreApiForNativeInterop.getInstance();
// api!.noop();
// api.echoAllNullableTypesWithoutRecursion(
// genericNIAllNullableTypesWithoutRecursion);
final NIAllClassesWrapper classWrapper = classWrapperMaker();
classWrapper.allTypes = null;
final NIAllClassesWrapper receivedClassWrapper =
api!.echoClassWrapper(classWrapper);
print(receivedClassWrapper);
} catch (e) {
setState(() {
status = 'Failed: $e';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,29 +224,29 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) {
// expect(receivedObject.allNullableTypes.aNullableString, sentString);
// });

// testWidgets('nested classes can serialize and deserialize correctly',
// (WidgetTester _) async {
// final NIHostIntegrationCoreApiForNativeInterop? api =
// NIHostIntegrationCoreApiForNativeInterop.getInstance();
// final NIAllClassesWrapper classWrapper = classWrapperMaker();
testWidgets('nested classes can serialize and deserialize correctly',
(WidgetTester _) async {
final NIHostIntegrationCoreApiForNativeInterop? api =
NIHostIntegrationCoreApiForNativeInterop.getInstance();
final NIAllClassesWrapper classWrapper = classWrapperMaker();
final NIAllClassesWrapper receivedClassWrapper =
api!.echoClassWrapper(classWrapper);

// final NIAllClassesWrapper receivedClassWrapper =
// api!.echoClassWrapper(classWrapper);
// expect(classWrapper, receivedClassWrapper);
// });
expect(classWrapper, receivedClassWrapper);
});

// testWidgets('nested null classes can serialize and deserialize correctly',
// (WidgetTester _) async {
// final NIHostIntegrationCoreApiForNativeInterop? api =
// NIHostIntegrationCoreApiForNativeInterop.getInstance();
// final NIAllClassesWrapper classWrapper = classWrapperMaker();
testWidgets('nested null classes can serialize and deserialize correctly',
(WidgetTester _) async {
final NIHostIntegrationCoreApiForNativeInterop? api =
NIHostIntegrationCoreApiForNativeInterop.getInstance();
final NIAllClassesWrapper classWrapper = classWrapperMaker();

// classWrapper.allTypes = null;
classWrapper.allTypes = null;

// final NIAllClassesWrapper receivedClassWrapper =
// api!.echoClassWrapper(classWrapper);
// expect(classWrapper, receivedClassWrapper);
// });
final NIAllClassesWrapper receivedClassWrapper =
api!.echoClassWrapper(classWrapper);
expect(classWrapper, receivedClassWrapper);
});

// testWidgets(
// 'Arguments of multiple types serialize and deserialize correctly',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -447,14 +447,14 @@ final NIAllTypes genericNIAllTypes = NIAllTypes(
// recursiveClassMap: allNullableTypesMap,
// );

// NIAllClassesWrapper classWrapperMaker() {
// return NIAllClassesWrapper(
NIAllClassesWrapper classWrapperMaker() {
return NIAllClassesWrapper(
// allNullableTypes: recursiveNIAllNullableTypes,
// allNullableTypesWithoutRecursion: genericNIAllNullableTypesWithoutRecursion,
// allTypes: genericNIAllTypes,
allNullableTypesWithoutRecursion: genericNIAllNullableTypesWithoutRecursion,
allTypes: genericNIAllTypes,
// classList: allTypesClassList,
// classMap: allTypesClassMap,
// nullableClassList: allNullableTypesWithoutRecursionClassList,
// nullableClassMap: allNullableTypesWithoutRecursionClassMap,
// );
// }
);
}
Loading