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

[pigeon] adds support for collections of enums and classes #7476

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
4 changes: 4 additions & 0 deletions packages/pigeon/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 22.0.1

* Validates enums and classes in collections.
tarrinneal marked this conversation as resolved.
Show resolved Hide resolved

## 22.0.0

* [dart] Changes codec to send int64 instead of int32.
Expand Down
6 changes: 3 additions & 3 deletions packages/pigeon/example/app/ios/Runner/Messages.g.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ private class MessagesPigeonCodecReader: FlutterStandardReader {
override func readValue(ofType type: UInt8) -> Any? {
switch type {
case 129:
let enumResultAsInt: Int? = nilOrValue(self.readValue() as? Int)
let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?)
if let enumResultAsInt = enumResultAsInt {
return Code(rawValue: enumResultAsInt)
}
Expand Down Expand Up @@ -191,8 +191,8 @@ class ExampleHostApiSetup {
if let api = api {
addChannel.setMessageHandler { message, reply in
let args = message as! [Any?]
let aArg = args[0] is Int64 ? args[0] as! Int64 : Int64(args[0] as! Int32)
let bArg = args[1] is Int64 ? args[1] as! Int64 : Int64(args[1] as! Int32)
let aArg = args[0] as! Int64
let bArg = args[1] as! Int64
tarrinneal marked this conversation as resolved.
Show resolved Hide resolved
do {
let result = try api.add(aArg, to: bArg)
reply(wrapResult(result))
Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/lib/generator_tools.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import 'ast.dart';
/// The current version of pigeon.
///
/// This must match the version in pubspec.yaml.
const String pigeonVersion = '22.0.0';
const String pigeonVersion = '22.0.1';

/// Read all the content from [stdin] to a String.
String readStdin() {
Expand Down
7 changes: 0 additions & 7 deletions packages/pigeon/lib/pigeon_lib.dart
Original file line number Diff line number Diff line change
Expand Up @@ -975,13 +975,6 @@ List<Error> _validateAst(Root root, String source) {
lineNumber: _calculateLineNumberNullable(source, field.offset),
));
}
if (customEnums.contains(typeArgument.baseName)) {
result.add(Error(
message:
'Enum types aren\'t supported in type arguments in "${field.name}" in class "${classDefinition.name}".',
lineNumber: _calculateLineNumberNullable(source, field.offset),
));
}
}
if (!(validTypes.contains(field.type.baseName) ||
customClasses.contains(field.type.baseName) ||
Expand Down
56 changes: 37 additions & 19 deletions packages/pigeon/lib/swift_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ class SwiftGenerator extends StructuredGenerator<SwiftOptions> {
indent.nest(1, () {
if (customType.type == CustomTypes.customEnum) {
indent.writeln(
'let enumResultAsInt: Int? = nilOrValue(self.readValue() as? Int)');
'let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?)');
indent.writeScoped('if let enumResultAsInt = enumResultAsInt {', '}',
() {
indent.writeln(
Expand Down Expand Up @@ -419,7 +419,7 @@ if (wrapped == nil) {
}

void _writeClassField(Indent indent, NamedType field, {bool addNil = true}) {
indent.add('${field.name}: ${_nullsafeSwiftTypeForDartType(field.type)}');
indent.add('${field.name}: ${_nullSafeSwiftTypeForDartType(field.type)}');
final String defaultNil = field.type.isNullable && addNil ? ' = nil' : '';
indent.add(defaultNil);
}
Expand Down Expand Up @@ -487,7 +487,16 @@ if (wrapped == nil) {
getFieldsInSerializationOrder(classDefinition).last == field
? ''
: ',';
indent.writeln('${field.name}: ${field.name}$comma');
// There's a swift bug that breaks force-casting nullable enums in maps.
final String forceUnwrapMapWithNullableEnums =
(field.type.baseName == 'Map' &&
!field.type.isNullable &&
field.type.typeArguments
.any((TypeDeclaration type) => type.isEnum))
? '!'
: '';
indent.writeln(
'${field.name}: ${field.name}$forceUnwrapMapWithNullableEnums$comma');
}
});
});
Expand Down Expand Up @@ -650,14 +659,10 @@ if (wrapped == nil) {
assert(!type.isVoid);
if (type.baseName == 'Object') {
return value + (type.isNullable ? '' : '!');
} else if (type.baseName == 'int') {
if (type.isNullable) {
// Nullable ints need to check for NSNull, and Int32 before casting can be done safely.
// This nested ternary is a necessary evil to avoid less efficient conversions.
return 'isNullish($value) ? nil : ($value is Int64? ? $value as! Int64? : Int64($value as! Int32))';
} else {
return '$value is Int64 ? $value as! Int64 : Int64($value as! Int32)';
}
// There's a swift bug that breaks force-casting nullable enums in maps.
tarrinneal marked this conversation as resolved.
Show resolved Hide resolved
} else if (type.baseName == 'Map' &&
type.typeArguments.any((TypeDeclaration type) => type.isEnum)) {
return '$value as? ${_swiftTypeForDartType(type)}';
} else if (type.isNullable) {
return 'nilOrValue($value)';
} else {
Expand Down Expand Up @@ -846,7 +851,13 @@ private func nilOrValue<T>(_ value: Any?) -> T? {
fieldType: fieldType,
type: returnType,
);
indent.writeln('completion(.success(result))');
// There is a swift bug with unwrapping maps of nullable Enums;
final String enumMapForceUnwrap = returnType.baseName == 'Map' &&
returnType.typeArguments
.any((TypeDeclaration type) => type.isEnum)
? '!'
: '';
indent.writeln('completion(.success(result$enumMapForceUnwrap))');
}
});
});
Expand Down Expand Up @@ -887,6 +898,12 @@ private func nilOrValue<T>(_ value: Any?) -> T? {
final String argName = _getSafeArgumentName(index, arg.namedType);
final String argIndex = 'args[$index]';
final String fieldType = _swiftTypeForDartType(arg.type);
// There is a swift bug with unwrapping maps of nullable Enums;
final String enumMapForceUnwrap = arg.type.baseName == 'Map' &&
arg.type.typeArguments
.any((TypeDeclaration type) => type.isEnum)
? '!'
: '';

_writeGenericCasting(
indent: indent,
Expand All @@ -896,9 +913,10 @@ private func nilOrValue<T>(_ value: Any?) -> T? {
type: arg.type);

if (arg.label == '_') {
methodArgument.add(argName);
methodArgument.add('$argName$enumMapForceUnwrap');
} else {
methodArgument.add('${arg.label ?? arg.name}: $argName');
methodArgument
.add('${arg.label ?? arg.name}: $argName$enumMapForceUnwrap');
}
});
}
Expand Down Expand Up @@ -1022,9 +1040,9 @@ String _swiftTypeForBuiltinGenericDartType(TypeDeclaration type) {
}
} else {
if (type.baseName == 'List') {
return '[${_nullsafeSwiftTypeForDartType(type.typeArguments.first)}]';
return '[${_nullSafeSwiftTypeForDartType(type.typeArguments.first)}]';
} else if (type.baseName == 'Map') {
return '[${_nullsafeSwiftTypeForDartType(type.typeArguments.first)}: ${_nullsafeSwiftTypeForDartType(type.typeArguments.last)}]';
return '[${_nullSafeSwiftTypeForDartType(type.typeArguments.first)}: ${_nullSafeSwiftTypeForDartType(type.typeArguments.last)}]';
} else {
return '${type.baseName}<${_flattenTypeArguments(type.typeArguments)}>';
}
Expand Down Expand Up @@ -1058,7 +1076,7 @@ String _swiftTypeForDartType(TypeDeclaration type) {
return _swiftTypeForBuiltinDartType(type) ?? type.baseName;
}

String _nullsafeSwiftTypeForDartType(TypeDeclaration type) {
String _nullSafeSwiftTypeForDartType(TypeDeclaration type) {
final String nullSafe = type.isNullable ? '?' : '';
return '${_swiftTypeForDartType(type)}$nullSafe';
}
Expand All @@ -1080,10 +1098,10 @@ String _getMethodSignature({
swiftFunction: swiftFunction,
);
final String returnTypeString =
returnType.isVoid ? 'Void' : _nullsafeSwiftTypeForDartType(returnType);
returnType.isVoid ? 'Void' : _nullSafeSwiftTypeForDartType(returnType);

final Iterable<String> types =
parameters.map((NamedType e) => _nullsafeSwiftTypeForDartType(e.type));
parameters.map((NamedType e) => _nullSafeSwiftTypeForDartType(e.type));
final Iterable<String> labels = indexMap(components.arguments,
(int index, _SwiftFunctionArgument argument) {
return argument.label ?? _getArgumentName(index, argument.namedType);
Expand Down
Loading