diff --git a/packages/pigeon/.gitignore b/packages/pigeon/.gitignore index 5af65c55eed..ae69a69b632 100644 --- a/packages/pigeon/.gitignore +++ b/packages/pigeon/.gitignore @@ -10,4 +10,4 @@ gradlew.bat local.properties gradle-wrapper.jar bin/pigeon.dart.dill - +**/subdirectory/does/not/exist/** diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index bec0d709714..e0c7d40a17c 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,5 +1,9 @@ -## NEXT +## 11.0.0 +* Adds primitive enum support. +* Fixes Objective-C nullable enums. +* **Breaking Change** Changes all nullable enums in Objective-C to be wrapped in custom classes. +* **Breaking Change** Changes all enums names in Objective-C to have class prefix. * Updates minimum supported SDK version to Flutter 3.7/Dart 2.19. ## 10.1.6 @@ -91,7 +95,7 @@ ## 9.1.1 * [swift] Removes experimental tags. -* [kotin] Removes experimental tags. +* [kotlin] Removes experimental tags. ## 9.1.0 diff --git a/packages/pigeon/README.md b/packages/pigeon/README.md index 26ee5bd5e5e..213e650c632 100644 --- a/packages/pigeon/README.md +++ b/packages/pigeon/README.md @@ -23,12 +23,9 @@ Currently pigeon supports generating: Pigeon uses the `StandardMessageCodec` so it supports [any datatype platform channels support](https://flutter.dev/docs/development/platform-integration/platform-channels#codec). -Custom classes and nested datatypes are also supported. +Custom classes, nested datatypes, and enums are also supported. -#### Enums - -Pigeon currently supports enum generation in class fields only. -See issue: [87307](https://github.com/flutter/flutter/issues/87307). +Nullable enums in Objective-C generated code will be wrapped in a class to allow for nullability. ### Synchronous and Asynchronous methods diff --git a/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java b/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java index f358afe2ebe..25bcda1c6db 100644 --- a/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java +++ b/packages/pigeon/example/app/android/app/src/main/java/io/flutter/plugins/Messages.java @@ -173,7 +173,7 @@ ArrayList toList() { Object description = list.get(1); pigeonResult.setDescription((String) description); Object code = list.get(2); - pigeonResult.setCode(code == null ? null : Code.values()[(int) code]); + pigeonResult.setCode(Code.values()[(int) code]); Object data = list.get(3); pigeonResult.setData((Map) data); return pigeonResult; diff --git a/packages/pigeon/example/app/ios/Runner/Messages.g.swift b/packages/pigeon/example/app/ios/Runner/Messages.g.swift index c95fc3edd7e..9c12267c489 100644 --- a/packages/pigeon/example/app/ios/Runner/Messages.g.swift +++ b/packages/pigeon/example/app/ios/Runner/Messages.g.swift @@ -13,6 +13,10 @@ import FlutterMacOS #error("Unsupported platform.") #endif +private func isNullish(_ value: Any?) -> Bool { + return value is NSNull || value == nil +} + private func wrapResult(_ result: Any?) -> [Any?] { return [result] } diff --git a/packages/pigeon/example/app/macos/Runner/messages.g.h b/packages/pigeon/example/app/macos/Runner/messages.g.h index f7cbe391105..64cf6e2ee56 100644 --- a/packages/pigeon/example/app/macos/Runner/messages.g.h +++ b/packages/pigeon/example/app/macos/Runner/messages.g.h @@ -18,6 +18,12 @@ typedef NS_ENUM(NSUInteger, PGNCode) { PGNCodeTwo = 1, }; +/// Wrapper for PGNCode to allow for nullability. +@interface PGNCodeBox : NSObject +@property(nonatomic, assign) PGNCode value; +- (instancetype)initWithValue:(PGNCode)value; +@end + @class PGNMessageData; @interface PGNMessageData : NSObject diff --git a/packages/pigeon/example/app/macos/Runner/messages.g.m b/packages/pigeon/example/app/macos/Runner/messages.g.m index 37b75fa068e..6610097ee67 100644 --- a/packages/pigeon/example/app/macos/Runner/messages.g.m +++ b/packages/pigeon/example/app/macos/Runner/messages.g.m @@ -16,6 +16,16 @@ #error File requires ARC to be enabled. #endif +@implementation PGNCodeBox +- (instancetype)initWithValue:(PGNCode)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + static NSArray *wrapResult(id result, FlutterError *error) { if (error) { return @[ diff --git a/packages/pigeon/lib/cpp_generator.dart b/packages/pigeon/lib/cpp_generator.dart index 6284f532ac8..67b7f506668 100644 --- a/packages/pigeon/lib/cpp_generator.dart +++ b/packages/pigeon/lib/cpp_generator.dart @@ -888,9 +888,14 @@ class CppSourceGenerator extends StructuredGenerator { indent.writeln( 'std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size);'); indent.writeln('const auto& $encodedReplyName = *response;'); - _writeEncodableValueArgumentUnwrapping(indent, returnType, - argName: successCallbackArgument, - encodableArgName: encodedReplyName); + _writeEncodableValueArgumentUnwrapping( + indent, + root, + returnType, + argName: successCallbackArgument, + encodableArgName: encodedReplyName, + apiType: ApiType.flutter, + ); } indent.writeln('on_success($successCallbackArgument);'); }); @@ -968,9 +973,19 @@ class CppSourceGenerator extends StructuredGenerator { indent.writeln('return;'); }); } - _writeEncodableValueArgumentUnwrapping(indent, hostType, - argName: argName, encodableArgName: encodableArgName); - methodArgument.add(argName); + _writeEncodableValueArgumentUnwrapping( + indent, + root, + hostType, + argName: argName, + encodableArgName: encodableArgName, + apiType: ApiType.host, + ); + final String unwrapEnum = + isEnum(root, arg.type) && arg.type.isNullable + ? ' ? &(*$argName) : nullptr' + : ''; + methodArgument.add('$argName$unwrapEnum'); }); } @@ -1198,6 +1213,10 @@ return EncodableValue(EncodableList{ final String errorGetter; const String nullValue = 'EncodableValue()'; + String enumPrefix = ''; + if (isEnum(root, returnType)) { + enumPrefix = '(int) '; + } if (returnType.isVoid) { nonErrorPath = '${prefix}wrapped.push_back($nullValue);'; errorCondition = 'output.has_value()'; @@ -1205,22 +1224,24 @@ return EncodableValue(EncodableList{ } else { final HostDatatype hostType = getHostDatatype(returnType, root.classes, root.enums, _shortBaseCppTypeForBuiltinDartType); + const String extractedValue = 'std::move(output).TakeValue()'; - final String wrapperType = - hostType.isBuiltin ? 'EncodableValue' : 'CustomEncodableValue'; + final String wrapperType = hostType.isBuiltin || isEnum(root, returnType) + ? 'EncodableValue' + : 'CustomEncodableValue'; if (returnType.isNullable) { // The value is a std::optional, so needs an extra layer of // handling. nonErrorPath = ''' ${prefix}auto output_optional = $extractedValue; ${prefix}if (output_optional) { -$prefix\twrapped.push_back($wrapperType(std::move(output_optional).value())); +$prefix\twrapped.push_back($wrapperType(${enumPrefix}std::move(output_optional).value())); $prefix} else { $prefix\twrapped.push_back($nullValue); $prefix}'''; } else { nonErrorPath = - '${prefix}wrapped.push_back($wrapperType($extractedValue));'; + '${prefix}wrapped.push_back($wrapperType($enumPrefix$extractedValue));'; } errorCondition = 'output.has_error()'; errorGetter = 'error'; @@ -1297,9 +1318,11 @@ ${prefix}reply(EncodableValue(std::move(wrapped)));'''; /// existing EncodableValue variable called [encodableArgName]. void _writeEncodableValueArgumentUnwrapping( Indent indent, + Root root, HostDatatype hostType, { required String argName, required String encodableArgName, + required ApiType apiType, }) { if (hostType.isNullable) { // Nullable arguments are always pointers, with nullptr corresponding to @@ -1320,6 +1343,22 @@ ${prefix}reply(EncodableValue(std::move(wrapped)));'''; } else if (hostType.isBuiltin) { indent.writeln( 'const auto* $argName = std::get_if<${hostType.datatype}>(&$encodableArgName);'); + } else if (hostType.isEnum) { + if (hostType.isNullable) { + final String valueVarName = '${argName}_value'; + indent.writeln( + 'const int64_t $valueVarName = $encodableArgName.IsNull() ? 0 : $encodableArgName.LongValue();'); + if (apiType == ApiType.flutter) { + indent.writeln( + 'const auto* $argName = $encodableArgName.IsNull() ? nullptr : &(${hostType.datatype})$valueVarName;'); + } else { + indent.writeln( + 'const auto $argName = $encodableArgName.IsNull() ? std::nullopt : std::make_optional<${hostType.datatype}>(static_cast<${hostType.datatype}>(${argName}_value));'); + } + } else { + indent.writeln( + 'const auto* $argName = &((${hostType.datatype})std::get($encodableArgName));'); + } } else { indent.writeln( 'const auto* $argName = &(std::any_cast(std::get($encodableArgName)));'); @@ -1342,6 +1381,9 @@ ${prefix}reply(EncodableValue(std::move(wrapped)));'''; } else if (hostType.isBuiltin) { indent.writeln( 'const auto& $argName = std::get<${hostType.datatype}>($encodableArgName);'); + } else if (hostType.isEnum) { + indent.writeln( + 'const ${hostType.datatype}& $argName = (${hostType.datatype})$encodableArgName.LongValue();'); } else { indent.writeln( 'const auto& $argName = std::any_cast(std::get($encodableArgName));'); @@ -1390,7 +1432,11 @@ String _getSafeArgumentName(int count, NamedType argument) => /// Returns a non-nullable variant of [type]. HostDatatype _nonNullableType(HostDatatype type) { return HostDatatype( - datatype: type.datatype, isBuiltin: type.isBuiltin, isNullable: false); + datatype: type.datatype, + isBuiltin: type.isBuiltin, + isNullable: false, + isEnum: type.isEnum, + ); } String _pascalCaseFromCamelCase(String camelCase) => diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart index d712ee54683..fe13c75148e 100644 --- a/packages/pigeon/lib/dart_generator.dart +++ b/packages/pigeon/lib/dart_generator.dart @@ -411,7 +411,7 @@ $resultAt != null final String leftHandSide = 'final $argType? $argName'; if (customEnumNames.contains(arg.type.baseName)) { indent.writeln( - '$leftHandSide = $argsArray[$count] == null ? null : $argType.values[$argsArray[$count] as int];'); + '$leftHandSide = $argsArray[$count] == null ? null : $argType.values[$argsArray[$count]! as int];'); } else { indent.writeln( '$leftHandSide = ($argsArray[$count] as $genericArgType?)${castCall.isEmpty ? '' : '?$castCall'};'); @@ -442,10 +442,15 @@ $resultAt != null } else { indent.writeln('final $returnType output = $call;'); } + const String returnExpression = 'output'; + final String nullability = + func.returnType.isNullable ? '?' : ''; + final String valueExtraction = + isEnum(root, func.returnType) ? '$nullability.index' : ''; final String returnStatement = isMockHandler - ? 'return [$returnExpression];' - : 'return $returnExpression;'; + ? 'return [$returnExpression$valueExtraction];' + : 'return $returnExpression$valueExtraction;'; indent.writeln(returnStatement); } }); @@ -487,6 +492,8 @@ $resultAt != null codecName = _getCodecName(api); _writeCodec(indent, codecName, api, root); } + final List customEnumNames = + root.enums.map((Enum x) => x.name).toList(); indent.newln(); bool first = true; addDocumentationComments( @@ -553,9 +560,21 @@ final BinaryMessenger? _binaryMessenger; final String nullHandler = func.returnType.isNullable ? (genericCastCall.isEmpty ? '' : '?') : '!'; - final String returnStatement = func.returnType.isVoid - ? 'return;' - : 'return $nullablyTypedAccessor$nullHandler$genericCastCall;'; + String returnStatement = 'return'; + if (customEnumNames.contains(returnType)) { + if (func.returnType.isNullable) { + returnStatement = + '$returnStatement ($accessor as int?) == null ? null : $returnType.values[$accessor! as int]'; + } else { + returnStatement = + '$returnStatement $returnType.values[$accessor! as int]'; + } + } else if (!func.returnType.isVoid) { + returnStatement = + '$returnStatement $nullablyTypedAccessor$nullHandler$genericCastCall'; + } + returnStatement = '$returnStatement;'; + indent.format(''' final List? replyList = \t\tawait channel.send($sendArgument) as List?; diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart index 19e05709cd2..b6e6f72b529 100644 --- a/packages/pigeon/lib/generator_tools.dart +++ b/packages/pigeon/lib/generator_tools.dart @@ -13,7 +13,7 @@ import 'ast.dart'; /// The current version of pigeon. /// /// This must match the version in pubspec.yaml. -const String pigeonVersion = '10.1.6'; +const String pigeonVersion = '11.0.0'; /// Read all the content from [stdin] to a String. String readStdin() { @@ -176,6 +176,7 @@ class HostDatatype { required this.datatype, required this.isBuiltin, required this.isNullable, + required this.isEnum, }); /// The [String] that can be printed into host code to represent the type. @@ -186,6 +187,9 @@ class HostDatatype { /// `true` if the type corresponds to a nullable Dart datatype. final bool isNullable; + + /// `true if the type is a custom enum. + final bool isEnum; } /// Calculates the [HostDatatype] for the provided [NamedType]. @@ -226,20 +230,32 @@ HostDatatype _getHostDatatype(TypeDeclaration type, List classes, ? customResolver(type.baseName) : type.baseName; return HostDatatype( - datatype: customName, isBuiltin: false, isNullable: type.isNullable); + datatype: customName, + isBuiltin: false, + isNullable: type.isNullable, + isEnum: false, + ); } else if (enums.map((Enum x) => x.name).contains(type.baseName)) { final String customName = customResolver != null ? customResolver(type.baseName) : type.baseName; return HostDatatype( - datatype: customName, isBuiltin: false, isNullable: type.isNullable); + datatype: customName, + isBuiltin: false, + isNullable: type.isNullable, + isEnum: true, + ); } else { throw Exception( 'unrecognized datatype ${fieldName == null ? '' : 'for field:"$fieldName" '}of type:"${type.baseName}"'); } } else { return HostDatatype( - datatype: datatype, isBuiltin: true, isNullable: type.isNullable); + datatype: datatype, + isBuiltin: true, + isNullable: type.isNullable, + isEnum: false, + ); } } @@ -574,6 +590,15 @@ String? deducePackageName(String mainDartFile) { } } +/// Enum to specify api type when generating code. +enum ApiType { + /// Flutter api. + flutter, + + /// Host api. + host, +} + /// Enum to specify which file will be generated for multi-file generators enum FileType { /// header file. diff --git a/packages/pigeon/lib/java_generator.dart b/packages/pigeon/lib/java_generator.dart index ac8d69ccbf5..8d58f37f231 100644 --- a/packages/pigeon/lib/java_generator.dart +++ b/packages/pigeon/lib/java_generator.dart @@ -382,7 +382,7 @@ class JavaGenerator extends StructuredGenerator { indent.writeln('Object $fieldVariable = list.get($index);'); if (customEnumNames.contains(field.type.baseName)) { indent.writeln( - '$result.$setter(${_intToEnum(fieldVariable, field.type.baseName)});'); + '$result.$setter(${_intToEnum(fieldVariable, field.type.baseName, field.type.isNullable)});'); } else { indent.writeln( '$result.$setter(${_castObject(field, root.classes, root.enums, fieldVariable)});'); @@ -452,6 +452,17 @@ class JavaGenerator extends StructuredGenerator { } }); + /// Returns an argument name that can be used in a context where it is possible to collide + /// and append `.index` to enums. + String getEnumSafeArgumentExpression(int count, NamedType argument) { + if (isEnum(root, argument.type)) { + return argument.type.isNullable + ? '${_getArgumentName(count, argument)}Arg == null ? null : ${_getArgumentName(count, argument)}Arg.index' + : '${_getArgumentName(count, argument)}Arg.index'; + } + return '${_getArgumentName(count, argument)}Arg'; + } + for (final Method func in api.methods) { final String channelName = makeChannelName(api, func, dartPackageName); final String returnType = func.returnType.isVoid @@ -469,12 +480,14 @@ class JavaGenerator extends StructuredGenerator { .map((NamedType e) => _nullsafeJavaTypeForDartType(e.type)); final Iterable argNames = indexMap(func.arguments, _getSafeArgumentName); + final Iterable enumSafeArgNames = + indexMap(func.arguments, getEnumSafeArgumentExpression); if (func.arguments.length == 1) { sendArgument = - 'new ArrayList(Collections.singletonList(${argNames.first}))'; + 'new ArrayList(Collections.singletonList(${enumSafeArgNames.first}))'; } else { sendArgument = - 'new ArrayList(Arrays.asList(${argNames.join(', ')}))'; + 'new ArrayList(Arrays.asList(${enumSafeArgNames.join(', ')}))'; } final String argsSignature = map2(argTypes, argNames, (String x, String y) => '$x $y') @@ -504,6 +517,14 @@ class JavaGenerator extends StructuredGenerator { if (func.returnType.baseName == 'int') { indent.writeln( '$returnType $output = channelReply == null ? null : ((Number) channelReply).longValue();'); + } else if (isEnum(root, func.returnType)) { + if (func.returnType.isNullable) { + indent.writeln( + '$returnType $output = channelReply == null ? null : $returnType.values()[(int) channelReply];'); + } else { + indent.writeln( + '$returnType $output = $returnType.values()[(int) channelReply];'); + } } else { indent.writeln( '$returnType $output = ${_cast('channelReply', javaType: returnType)};'); @@ -673,6 +694,7 @@ class JavaGenerator extends StructuredGenerator { indent.nest(2, () { indent.write('(message, reply) -> '); indent.addScoped('{', '});', () { + String enumTag = ''; final String returnType = method.returnType.isVoid ? 'Void' : _javaTypeForDartType(method.returnType); @@ -695,7 +717,8 @@ class JavaGenerator extends StructuredGenerator { : argName; String accessor = 'args.get($index)'; if (isEnum(root, arg.type)) { - accessor = _intToEnum(accessor, arg.type.baseName); + accessor = _intToEnum( + accessor, arg.type.baseName, arg.type.isNullable); } else if (argType != 'Object') { accessor = _cast(accessor, javaType: argType); } @@ -706,12 +729,17 @@ class JavaGenerator extends StructuredGenerator { if (method.isAsynchronous) { final String resultValue = method.returnType.isVoid ? 'null' : 'result'; + if (isEnum(root, method.returnType)) { + enumTag = method.returnType.isNullable + ? ' == null ? null : $resultValue.index' + : '.index'; + } const String resultName = 'resultCallback'; indent.format(''' Result<$returnType> $resultName = \t\tnew Result<$returnType>() { \t\t\tpublic void success($returnType result) { -\t\t\t\twrapped.add(0, $resultValue); +\t\t\t\twrapped.add(0, $resultValue$enumTag); \t\t\t\treply.reply(wrapped); \t\t\t} @@ -734,8 +762,13 @@ Result<$returnType> $resultName = indent.writeln('$call;'); indent.writeln('wrapped.add(0, null);'); } else { + if (isEnum(root, method.returnType)) { + enumTag = method.returnType.isNullable + ? ' == null ? null : output.index' + : '.index'; + } indent.writeln('$returnType output = $call;'); - indent.writeln('wrapped.add(0, output);'); + indent.writeln('wrapped.add(0, output$enumTag);'); } }); indent.add(' catch (Throwable exception) '); @@ -906,8 +939,9 @@ String _getCodecName(Api api) => '${api.name}Codec'; /// Converts an expression that evaluates to an nullable int to an expression /// that evaluates to a nullable enum. -String _intToEnum(String expression, String enumName) => - '$expression == null ? null : $enumName.values()[(int) $expression]'; +String _intToEnum(String expression, String enumName, bool nullable) => nullable + ? '$expression == null ? null : $enumName.values()[(int) $expression]' + : '$enumName.values()[(int) $expression]'; String _getArgumentName(int count, NamedType argument) => argument.name.isEmpty ? 'arg$count' : argument.name; diff --git a/packages/pigeon/lib/kotlin_generator.dart b/packages/pigeon/lib/kotlin_generator.dart index 78472df269f..da6faf40470 100644 --- a/packages/pigeon/lib/kotlin_generator.dart +++ b/packages/pigeon/lib/kotlin_generator.dart @@ -282,10 +282,11 @@ class KotlinGenerator extends StructuredGenerator { }); } else if (isInt) { indent.write('val ${field.name} = $listValue'); - indent.addln('.let { ${_cast(listValue, type: field.type)} }'); + indent.addln( + '.let { ${_cast(root, indent, listValue, type: field.type)} }'); } else { indent.writeln( - 'val ${field.name} = ${_cast(listValue, type: field.type)}'); + 'val ${field.name} = ${_cast(root, indent, listValue, type: field.type)}'); } } else { if (!hostDatatype.isBuiltin && @@ -298,10 +299,11 @@ class KotlinGenerator extends StructuredGenerator { 'val ${field.name} = $fieldType.ofRaw($listValue as Int)!!'); } else if (isInt) { indent.write('val ${field.name} = $listValue'); - indent.addln('.let { ${_cast(listValue, type: field.type)} }'); + indent.addln( + '.let { ${_cast(root, indent, listValue, type: field.type)} }'); } else { indent.writeln( - 'val ${field.name} = ${_cast(listValue, type: field.type)}'); + 'val ${field.name} = ${_cast(root, indent, listValue, type: field.type)}'); } } }); @@ -403,7 +405,11 @@ class KotlinGenerator extends StructuredGenerator { .map((NamedType e) => _nullsafeKotlinTypeForDartType(e.type)); final Iterable argNames = indexMap(func.arguments, _getSafeArgumentName); - sendArgument = 'listOf(${argNames.join(', ')})'; + final Iterable enumSafeArgNames = indexMap( + func.arguments, + (int count, NamedType type) => + _getEnumSafeArgumentExpression(root, count, type)); + sendArgument = 'listOf(${enumSafeArgNames.join(', ')})'; final String argsSignature = map2(argTypes, argNames, (String type, String name) => '$name: $type').join(', '); if (func.returnType.isVoid) { @@ -425,8 +431,15 @@ class KotlinGenerator extends StructuredGenerator { }); } else { indent.addScoped('{', '}', () { - indent.writeln( - 'val result = ${_cast('it', type: func.returnType)}'); + // Nullable enums require special handling. + if (isEnum(root, func.returnType) && func.returnType.isNullable) { + indent.writeScoped('val result = (it as Int?)?.let {', '}', () { + indent.writeln('${func.returnType.baseName}.ofRaw(it)'); + }); + } else { + indent.writeln( + 'val result = ${_cast(root, indent, 'it', type: func.returnType)}'); + } indent.writeln('callback(result)'); }); } @@ -556,7 +569,7 @@ class KotlinGenerator extends StructuredGenerator { final String argName = _getSafeArgumentName(index, arg); final String argIndex = 'args[$index]'; indent.writeln( - 'val $argName = ${_castForceUnwrap(argIndex, arg.type, root)}'); + 'val $argName = ${_castForceUnwrap(argIndex, arg.type, root, indent)}'); methodArguments.add(argName); }); } @@ -575,11 +588,17 @@ class KotlinGenerator extends StructuredGenerator { indent.writeln('reply.reply(wrapError(error))'); }, addTrailingNewline: false); indent.addScoped(' else {', '}', () { + final String enumTagNullablePrefix = + method.returnType.isNullable ? '?' : '!!'; + final String enumTag = isEnum(root, method.returnType) + ? '$enumTagNullablePrefix.raw' + : ''; if (method.returnType.isVoid) { indent.writeln('reply.reply(wrapResult(null))'); } else { indent.writeln('val data = result.getOrNull()'); - indent.writeln('reply.reply(wrapResult(data))'); + indent + .writeln('reply.reply(wrapResult(data$enumTag))'); } }); }); @@ -591,7 +610,13 @@ class KotlinGenerator extends StructuredGenerator { indent.writeln(call); indent.writeln('wrapped = listOf(null)'); } else { - indent.writeln('wrapped = listOf($call)'); + String enumTag = ''; + if (isEnum(root, method.returnType)) { + final String safeUnwrap = + method.returnType.isNullable ? '?' : ''; + enumTag = '$safeUnwrap.raw'; + } + indent.writeln('wrapped = listOf($call$enumTag)'); } }, addTrailingNewline: false); indent.add(' catch (exception: Throwable) '); @@ -736,24 +761,37 @@ String _getCodecName(Api api) => '${api.name}Codec'; String _getArgumentName(int count, NamedType argument) => argument.name.isEmpty ? 'arg$count' : argument.name; +/// Returns an argument name that can be used in a context where it is possible to collide +/// and append `.index` to enums. +String _getEnumSafeArgumentExpression( + Root root, int count, NamedType argument) { + if (isEnum(root, argument.type)) { + return argument.type.isNullable + ? '${_getArgumentName(count, argument)}Arg?.raw' + : '${_getArgumentName(count, argument)}Arg.raw'; + } + return '${_getArgumentName(count, argument)}Arg'; +} + /// Returns an argument name that can be used in a context where it is possible to collide. String _getSafeArgumentName(int count, NamedType argument) => '${_getArgumentName(count, argument)}Arg'; -String _castForceUnwrap(String value, TypeDeclaration type, Root root) { +String _castForceUnwrap( + String value, TypeDeclaration type, Root root, Indent indent) { if (isEnum(root, type)) { final String forceUnwrap = type.isNullable ? '' : '!!'; final String nullableConditionPrefix = - type.isNullable ? '$value == null ? null : ' : ''; + type.isNullable ? 'if ($value == null) null else ' : ''; return '$nullableConditionPrefix${_kotlinTypeForDartType(type)}.ofRaw($value as Int)$forceUnwrap'; } else { // The StandardMessageCodec can give us [Integer, Long] for // a Dart 'int'. To keep things simple we just use 64bit // longs in Pigeon with Kotlin. if (type.baseName == 'int') { - return '$value.let { ${_cast(value, type: type)} }'; + return '$value.let { ${_cast(root, indent, value, type: type)} }'; } else { - return _cast(value, type: type); + return _cast(root, indent, value, type: type); } } } @@ -819,7 +857,8 @@ String _nullsafeKotlinTypeForDartType(TypeDeclaration type) { } /// Returns an expression to cast [variable] to [kotlinType]. -String _cast(String variable, {required TypeDeclaration type}) { +String _cast(Root root, Indent indent, String variable, + {required TypeDeclaration type}) { // Special-case Any, since no-op casts cause warnings. final String typeString = _kotlinTypeForDartType(type); if (type.isNullable && typeString == 'Any') { @@ -828,6 +867,14 @@ String _cast(String variable, {required TypeDeclaration type}) { if (typeString == 'Int' || typeString == 'Long') { return _castInt(type.isNullable); } + if (isEnum(root, type)) { + if (type.isNullable) { + return '($variable as Int?)?.let {\n' + '${indent.str} $typeString.ofRaw(it)\n' + '${indent.str}}'; + } + return '${type.baseName}.ofRaw($variable as Int)!!'; + } return '$variable as ${_nullsafeKotlinTypeForDartType(type)}'; } diff --git a/packages/pigeon/lib/objc_generator.dart b/packages/pigeon/lib/objc_generator.dart index 53e46725cff..baac4e34579 100644 --- a/packages/pigeon/lib/objc_generator.dart +++ b/packages/pigeon/lib/objc_generator.dart @@ -141,7 +141,8 @@ class ObjcHeaderGenerator extends StructuredGenerator { Enum anEnum, { required String dartPackageName, }) { - final String enumName = _className(generatorOptions.prefix, anEnum.name); + final String enumName = + _enumName(anEnum.name, prefix: generatorOptions.prefix); indent.newln(); addDocumentationComments( indent, anEnum.documentationComments, _docCommentSpec); @@ -156,6 +157,17 @@ class ObjcHeaderGenerator extends StructuredGenerator { '$enumName${member.name[0].toUpperCase()}${member.name.substring(1)} = $index,'); }); }); + _writeEnumWrapper(indent, enumName); + } + + void _writeEnumWrapper(Indent indent, String enumName) { + indent.newln(); + indent.writeln('/// Wrapper for $enumName to allow for nullability.'); + indent.writeln( + '@interface ${_enumName(enumName, prefix: '', box: true)} : NSObject'); + indent.writeln('@property(nonatomic, assign) $enumName value;'); + indent.writeln('- (instancetype)initWithValue:($enumName)value;'); + indent.writeln('@end'); } @override @@ -205,7 +217,14 @@ class ObjcHeaderGenerator extends StructuredGenerator { indent.writeln('- (instancetype)init NS_UNAVAILABLE;'); } _writeObjcSourceClassInitializerDeclaration( - indent, klass, classes, enums, prefix); + indent, + generatorOptions, + root, + klass, + classes, + enums, + prefix, + ); indent.addln(';'); } for (final NamedType field in getFieldsInSerializationOrder(klass)) { @@ -215,20 +234,26 @@ class ObjcHeaderGenerator extends StructuredGenerator { enums, (TypeDeclaration x) => _objcTypePtrForPrimitiveDartType(prefix, x), customResolver: customEnumNames.contains(field.type.baseName) - ? (String x) => _className(prefix, x) + ? (String x) => _enumName(x, prefix: prefix) : (String x) => '${_className(prefix, x)} *'); late final String propertyType; addDocumentationComments( indent, field.documentationComments, _docCommentSpec); - if (customEnumNames.contains(field.type.baseName)) { + if (customEnumNames.contains(field.type.baseName) && + !field.type.isNullable) { propertyType = 'assign'; } else { propertyType = _propertyTypeForDartType(field); } - final String nullability = - _isNullable(hostDatatype, field.type) ? ', nullable' : ''; + final String nullability = field.type.isNullable ? ', nullable' : ''; + final String fieldType = isEnum(root, field.type) && field.type.isNullable + ? _enumName(field.type.baseName, + suffix: ' *', + prefix: generatorOptions.prefix, + box: field.type.isNullable) + : hostDatatype.datatype; indent.writeln( - '@property(nonatomic, $propertyType$nullability) ${hostDatatype.datatype} ${field.name};'); + '@property(nonatomic, $propertyType$nullability) $fieldType ${field.name};'); } indent.writeln('@end'); indent.newln(); @@ -291,7 +316,8 @@ class ObjcHeaderGenerator extends StructuredGenerator { for (final Method func in api.methods) { final _ObjcPtr returnType = _objcTypeForDartType(generatorOptions.prefix, func.returnType); - final String callbackType = _callbackForType(func.returnType, returnType); + final String callbackType = + _callbackForType(root, func.returnType, returnType, generatorOptions); addDocumentationComments( indent, func.documentationComments, _docCommentSpec); @@ -302,6 +328,7 @@ class ObjcHeaderGenerator extends StructuredGenerator { lastArgName: 'completion', lastArgType: callbackType, isEnum: (TypeDeclaration t) => isEnum(root, t), + root: root, )};'); } indent.writeln('@end'); @@ -333,20 +360,32 @@ class ObjcHeaderGenerator extends StructuredGenerator { String? lastArgName; String? lastArgType; String? returnType; + final String enumReturnType = _enumName( + returnTypeName.baseName, + suffix: func.returnType.isNullable ? ' *_Nullable' : '', + prefix: generatorOptions.prefix, + box: func.returnType.isNullable, + ); if (func.isAsynchronous) { returnType = 'void'; + lastArgName = 'completion'; if (func.returnType.isVoid) { lastArgType = 'void (^)(FlutterError *_Nullable)'; - lastArgName = 'completion'; + } else if (isEnum(root, func.returnType)) { + lastArgType = 'void (^)($enumReturnType, FlutterError *_Nullable)'; } else { lastArgType = - 'void (^)(${returnTypeName.ptr}_Nullable, FlutterError *_Nullable)'; - lastArgName = 'completion'; + 'void (^)(${returnTypeName.withPtr}_Nullable, FlutterError *_Nullable)'; } } else { - returnType = func.returnType.isVoid - ? 'void' - : 'nullable ${returnTypeName.ptr.trim()}'; + if (func.returnType.isVoid) { + returnType = 'void'; + } else if (isEnum(root, func.returnType)) { + returnType = enumReturnType; + } else { + returnType = 'nullable ${returnTypeName.withPtr.trim()}'; + } + lastArgType = 'FlutterError *_Nullable *_Nonnull'; lastArgName = 'error'; } @@ -367,6 +406,7 @@ class ObjcHeaderGenerator extends StructuredGenerator { lastArgName: lastArgName, lastArgType: lastArgType, isEnum: (TypeDeclaration t) => isEnum(root, t), + root: root, ); indent.writeln('$signature;'); } @@ -420,6 +460,33 @@ class ObjcSourceGenerator extends StructuredGenerator { indent.newln(); } + @override + void writeEnum( + ObjcOptions generatorOptions, + Root root, + Indent indent, + Enum anEnum, { + required String dartPackageName, + }) { + final String enumName = + _enumName(anEnum.name, prefix: generatorOptions.prefix); + addDocumentationComments( + indent, anEnum.documentationComments, _docCommentSpec); + indent.writeln( + '@implementation ${_enumName(enumName, prefix: '', box: true)}'); + indent.writeScoped('- (instancetype)initWithValue:($enumName)value {', '}', + () { + indent.writeln('self = [super init];'); + indent.writeScoped('if (self) {', '}', () { + indent.writeln('_value = value;'); + }); + + indent.writeln('return self;'); + }); + indent.writeln('@end'); + indent.newln(); + } + @override void writeDataClasses( ObjcOptions generatorOptions, @@ -522,8 +589,16 @@ class ObjcSourceGenerator extends StructuredGenerator { enumerate(getFieldsInSerializationOrder(klass), (int index, final NamedType field) { if (customEnumNames.contains(field.type.baseName)) { - indent.writeln( - '$resultName.${field.name} = [${_listGetter(customClassNames, 'list', field, index, generatorOptions.prefix)} integerValue];'); + if (field.type.isNullable) { + indent.writeln( + 'NSNumber *${field.name}AsNumber = GetNullableObjectAtIndex(list, $index);'); + indent.writeln( + '${_enumName(field.type.baseName, suffix: ' *', prefix: generatorOptions.prefix, box: true)}${field.name} = ${field.name}AsNumber == nil ? nil : [[${_enumName(field.type.baseName, prefix: generatorOptions.prefix, box: true)} alloc] initWithValue: [${field.name}AsNumber integerValue]];'); + indent.writeln('$resultName.${field.name} = ${field.name};'); + } else { + indent.writeln( + '$resultName.${field.name} = [${_listGetter(customClassNames, 'list', field, index, generatorOptions.prefix)} integerValue];'); + } } else { indent.writeln( '$resultName.${field.name} = ${_listGetter(customClassNames, 'list', field, index, generatorOptions.prefix)};'); @@ -637,18 +712,31 @@ class ObjcSourceGenerator extends StructuredGenerator { void _writeChannelApiBinding(ObjcOptions generatorOptions, Root root, Indent indent, String apiName, Method func, String channel) { - void unpackArgs(String variable, Iterable argNames) { + void unpackArgs(String variable) { indent.writeln('NSArray *args = $variable;'); - map3(wholeNumbers.take(func.arguments.length), argNames, func.arguments, - (int count, String argName, NamedType arg) { + int count = 0; + for (final NamedType arg in func.arguments) { + final String argName = _getSafeArgName(count, arg); if (isEnum(root, arg.type)) { - return '${_className(generatorOptions.prefix, arg.type.baseName)} $argName = [GetNullableObjectAtIndex(args, $count) integerValue];'; + final String className = + _className(generatorOptions.prefix, arg.type.baseName); + if (arg.type.isNullable) { + indent.writeln( + 'NSNumber *${argName}AsNumber = GetNullableObjectAtIndex(args, $count);'); + indent.writeln( + '${_enumName(arg.type.baseName, suffix: ' *', prefix: '', box: true)}$argName = ${argName}AsNumber == nil ? nil : [[${_enumName(arg.type.baseName, prefix: generatorOptions.prefix, box: true)} alloc] initWithValue: [${argName}AsNumber integerValue]];'); + } else { + indent.writeln( + '$className $argName = [GetNullableObjectAtIndex(args, $count) integerValue];'); + } } else { final _ObjcPtr argType = _objcTypeForDartType(generatorOptions.prefix, arg.type); - return '${argType.ptr}$argName = GetNullableObjectAtIndex(args, $count);'; + indent.writeln( + '${argType.withPtr}$argName = GetNullableObjectAtIndex(args, $count);'); } - }).forEach(indent.writeln); + count++; + } } void writeAsyncBindings(Iterable selectorComponents, @@ -670,16 +758,35 @@ class ObjcSourceGenerator extends StructuredGenerator { } } else { const String callback = 'callback(wrapResult(output, error));'; + String returnTypeString = '${returnType.withPtr}_Nullable output'; + const String numberOutput = 'NSNumber *output ='; + final String enumConversionExpression = func.returnType.isNullable + ? 'enumValue == nil ? nil : [NSNumber numberWithInteger:enumValue.value];' + : '[NSNumber numberWithInteger:enumValue];'; + if (isEnum(root, func.returnType)) { + if (func.returnType.isNullable) { + returnTypeString = + '${_enumName(returnType.baseName, suffix: ' *_Nullable', prefix: generatorOptions.prefix, box: true)} enumValue'; + } else { + returnTypeString = '${returnType.baseName} enumValue'; + } + } if (func.arguments.isEmpty) { indent.writeScoped( - '[api ${selectorComponents.first}:^(${returnType.ptr}_Nullable output, FlutterError *_Nullable error) {', + '[api ${selectorComponents.first}:^($returnTypeString, FlutterError *_Nullable error) {', '}];', () { + if (isEnum(root, func.returnType)) { + indent.writeln('$numberOutput $enumConversionExpression'); + } indent.writeln(callback); }); } else { indent.writeScoped( - '[api $callSignature ${selectorComponents.last}:^(${returnType.ptr}_Nullable output, FlutterError *_Nullable error) {', + '[api $callSignature ${selectorComponents.last}:^($returnTypeString, FlutterError *_Nullable error) {', '}];', () { + if (isEnum(root, func.returnType)) { + indent.writeln('$numberOutput $enumConversionExpression'); + } indent.writeln(callback); }); } @@ -692,7 +799,20 @@ class ObjcSourceGenerator extends StructuredGenerator { indent.writeln('$call;'); indent.writeln('callback(wrapResult(nil, error));'); } else { - indent.writeln('${returnType.ptr}output = $call;'); + if (isEnum(root, func.returnType)) { + if (func.returnType.isNullable) { + indent.writeln( + '${_enumName(func.returnType.baseName, suffix: ' *', prefix: generatorOptions.prefix, box: true)} enumBox = $call;'); + indent.writeln( + 'NSNumber *output = enumBox == nil ? nil : [NSNumber numberWithInteger:enumBox.value];'); + } else { + indent.writeln('${returnType.baseName} enumValue = $call;'); + indent.writeln( + 'NSNumber *output = [NSNumber numberWithInteger:enumValue];'); + } + } else { + indent.writeln('${returnType.withPtr}output = $call;'); + } indent.writeln('callback(wrapResult(output, error));'); } } @@ -718,7 +838,7 @@ class ObjcSourceGenerator extends StructuredGenerator { return '$selectorComponent:$argName'; }).join(' '); if (func.arguments.isNotEmpty) { - unpackArgs('message', argNames); + unpackArgs('message'); } if (func.isAsynchronous) { writeAsyncBindings(selectorComponents, callSignature, returnType); @@ -803,7 +923,14 @@ static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) { String className, ) { _writeObjcSourceClassInitializerDeclaration( - indent, klass, root.classes, root.enums, languageOptions.prefix); + indent, + languageOptions, + root, + klass, + root.classes, + root.enums, + languageOptions.prefix, + ); indent.writeScoped(' {', '}', () { const String result = 'pigeonResult'; indent.writeln('$className* $result = [[$className alloc] init];'); @@ -927,16 +1054,32 @@ static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) { }) { final _ObjcPtr returnType = _objcTypeForDartType(languageOptions.prefix, func.returnType); - final String callbackType = _callbackForType(func.returnType, returnType); + final String callbackType = + _callbackForType(root, func.returnType, returnType, languageOptions); String argNameFunc(int count, NamedType arg) => _getSafeArgName(count, arg); - final Iterable argNames = indexMap(func.arguments, argNameFunc); String sendArgument; if (func.arguments.isEmpty) { sendArgument = 'nil'; } else { - String makeVarOrNSNullExpression(String x) => '$x ?: [NSNull null]'; - sendArgument = '@[${argNames.map(makeVarOrNSNullExpression).join(', ')}]'; + int count = 0; + String makeVarOrNSNullExpression(NamedType arg) { + String varExpression = '${argNameFunc(count, arg)} ?: [NSNull null]'; + if (isEnum(root, arg.type)) { + if (arg.type.isNullable) { + varExpression = + '${argNameFunc(count, arg)} == nil ? [NSNull null] : [NSNumber numberWithInteger:${argNameFunc(count, arg)}.value]'; + } else { + varExpression = + '[NSNumber numberWithInteger: ${argNameFunc(count, arg)}]'; + } + } + count++; + return varExpression; + } + + sendArgument = + '@[${func.arguments.map(makeVarOrNSNullExpression).join(', ')}]'; } indent.write(_makeObjcSignature( func: func, @@ -946,6 +1089,7 @@ static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) { lastArgType: callbackType, argNameFunc: argNameFunc, isEnum: (TypeDeclaration t) => isEnum(root, t), + root: root, )); indent.addScoped(' {', '}', () { indent.writeln('FlutterBasicMessageChannel *channel ='); @@ -965,7 +1109,19 @@ static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) { if (func.returnType.isVoid) { indent.writeln('completion(nil);'); } else { - indent.writeln('${returnType.ptr}output = reply;'); + if (isEnum(root, func.returnType)) { + if (func.returnType.isNullable) { + indent.writeln( + 'NSNumber *outputAsNumber = reply == [NSNull null] ? nil : reply;'); + indent.writeln( + '${_enumName(returnType.baseName, suffix: ' *', prefix: languageOptions.prefix, box: true)}output = outputAsNumber == nil ? nil : [[${_enumName(returnType.baseName, prefix: languageOptions.prefix, box: true)} alloc] initWithValue: [outputAsNumber integerValue]];'); + } else { + indent.writeln( + '${returnType.baseName} output = [reply integerValue];'); + } + } else { + indent.writeln('${returnType.withPtr}output = reply;'); + } indent.writeln('completion(output, nil);'); } }); @@ -976,8 +1132,14 @@ static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) { /// Writes the method declaration for the initializer. /// /// Example '+ (instancetype)makeWithFoo:(NSString *)foo' -void _writeObjcSourceClassInitializerDeclaration(Indent indent, Class klass, - List classes, List enums, String? prefix) { +void _writeObjcSourceClassInitializerDeclaration( + Indent indent, + ObjcOptions generatorOptions, + Root root, + Class klass, + List classes, + List enums, + String? prefix) { final List customEnumNames = enums.map((Enum x) => x.name).toList(); indent.write('+ (instancetype)makeWith'); bool isFirst = true; @@ -997,15 +1159,20 @@ void _writeObjcSourceClassInitializerDeclaration(Indent indent, Class klass, enums, (TypeDeclaration x) => _objcTypePtrForPrimitiveDartType(prefix, x), customResolver: customEnumNames.contains(field.type.baseName) - ? (String x) => _className(prefix, x) + ? (String x) => field.type.isNullable + ? _enumName(x, suffix: ' *', prefix: prefix, box: true) + : _enumName(x, prefix: prefix) : (String x) => '${_className(prefix, x)} *'); - final String nullable = - _isNullable(hostDatatype, field.type) ? 'nullable ' : ''; + final String nullable = field.type.isNullable ? 'nullable ' : ''; printer('$label:($nullable${hostDatatype.datatype})${field.name}'); } }); } +String _enumName(String name, + {required String? prefix, String suffix = '', bool box = false}) => + '${prefix ?? ''}$name${box ? 'Box' : ''}$suffix'; + /// Calculates the ObjC class name, possibly prefixed. String _className(String? prefix, String className) { if (prefix != null) { @@ -1016,10 +1183,18 @@ String _className(String? prefix, String className) { } /// Calculates callback block signature for async methods. -String _callbackForType(TypeDeclaration type, _ObjcPtr objcType) { - return type.isVoid - ? 'void (^)(FlutterError *_Nullable)' - : 'void (^)(${objcType.ptr}_Nullable, FlutterError *_Nullable)'; +String _callbackForType( + Root root, TypeDeclaration type, _ObjcPtr objcType, ObjcOptions options) { + if (type.isVoid) { + return 'void (^)(FlutterError *_Nullable)'; + } else if (isEnum(root, type)) { + if (type.isNullable) { + return 'void (^)(${_enumName(objcType.baseName, suffix: ' *_Nullable', prefix: options.prefix, box: true)}, FlutterError *_Nullable)'; + } + return 'void (^)(${_enumName(objcType.baseName, prefix: options.prefix)}, FlutterError *_Nullable)'; + } else { + return 'void (^)(${objcType.withPtr}_Nullable, FlutterError *_Nullable)'; + } } /// Represents an ObjC pointer (ex 'id', 'NSString *'). @@ -1027,7 +1202,8 @@ class _ObjcPtr { const _ObjcPtr({required this.baseName}) : hasAsterisk = baseName != 'id'; final String baseName; final bool hasAsterisk; - String get ptr => '$baseName${hasAsterisk ? ' *' : ' '}'; + String get withPtr => '$baseName${hasAsterisk ? ' *' : ' '}'; + String get ptr => hasAsterisk ? '*' : ''; } /// Maps between Dart types to ObjC pointer types (ex 'String' => 'NSString *'). @@ -1051,7 +1227,7 @@ const Map _objcTypeForDartTypeMap = { String _flattenTypeArguments(String? classPrefix, List args) { final String result = args .map((TypeDeclaration e) => - _objcTypeForDartType(classPrefix, e).ptr.trim()) + _objcTypeForDartType(classPrefix, e).withPtr.trim()) .join(', '); return result; } @@ -1059,7 +1235,7 @@ String _flattenTypeArguments(String? classPrefix, List args) { String? _objcTypePtrForPrimitiveDartType( String? classPrefix, TypeDeclaration type) { return _objcTypeForDartTypeMap.containsKey(type.baseName) - ? _objcTypeForDartType(classPrefix, type).ptr + ? _objcTypeForDartType(classPrefix, type).withPtr : null; } @@ -1099,9 +1275,6 @@ String _propertyTypeForDartType(NamedType field) { } } -bool _isNullable(HostDatatype hostDatatype, TypeDeclaration type) => - hostDatatype.datatype.contains('*') && type.isNullable; - /// Generates the name of the codec that will be generated. String _getCodecName(String? prefix, String className) => '${_className(prefix, className)}Codec'; @@ -1160,9 +1333,12 @@ String _makeObjcSignature({ required String lastArgType, required String lastArgName, required bool Function(TypeDeclaration) isEnum, + required Root root, String Function(int, NamedType)? argNameFunc, }) { - argNameFunc = argNameFunc ?? (int _, NamedType e) => e.name; + argNameFunc = argNameFunc ?? + (int _, NamedType e) => + e.type.isNullable && isEnum(e.type) ? '${e.name}Boxed' : e.name; final Iterable argNames = followedByOne(indexMap(func.arguments, argNameFunc), lastArgName); final Iterable selectorComponents = @@ -1170,11 +1346,11 @@ String _makeObjcSignature({ final Iterable argTypes = followedByOne( func.arguments.map((NamedType arg) { if (isEnum(arg.type)) { - return _className(options.prefix, arg.type.baseName); + return '${arg.type.isNullable ? 'nullable ' : ''}${_enumName(arg.type.baseName, suffix: arg.type.isNullable ? ' *' : '', prefix: options.prefix, box: arg.type.isNullable)}'; } else { final String nullable = arg.type.isNullable ? 'nullable ' : ''; final _ObjcPtr argType = _objcTypeForDartType(options.prefix, arg.type); - return '$nullable${argType.ptr.trim()}'; + return '$nullable${argType.withPtr.trim()}'; } }), lastArgType, @@ -1212,6 +1388,9 @@ String _arrayValue(Set customClassNames, Set customEnumNames, if (customClassNames.contains(field.type.baseName)) { return '(self.${field.name} ? [self.${field.name} toList] : [NSNull null])'; } else if (customEnumNames.contains(field.type.baseName)) { + if (field.type.isNullable) { + return '(self.${field.name} == nil ? [NSNull null] : [NSNumber numberWithInteger:self.${field.name}.value])'; + } return '@(self.${field.name})'; } else { return '(self.${field.name} ?: [NSNull null])'; diff --git a/packages/pigeon/lib/pigeon_lib.dart b/packages/pigeon/lib/pigeon_lib.dart index 10a6af57b0f..81bbb90c04e 100644 --- a/packages/pigeon/lib/pigeon_lib.dart +++ b/packages/pigeon/lib/pigeon_lib.dart @@ -787,32 +787,6 @@ List _validateAst(Root root, String source) { } for (final Api api in root.apis) { for (final Method method in api.methods) { - if (api.location == ApiLocation.flutter && - method.arguments.isNotEmpty && - method.arguments.any((NamedType element) => - customEnums.contains(element.type.baseName))) { - result.add(Error( - message: - 'Enums aren\'t yet supported for primitive arguments in FlutterApis: "${method.arguments[0]}" in API: "${api.name}" method: "${method.name}" (https://github.com/flutter/flutter/issues/87307)', - lineNumber: _calculateLineNumberNullable(source, method.offset), - )); - } - if (customEnums.contains(method.returnType.baseName)) { - result.add(Error( - message: - 'Enums aren\'t yet supported for primitive return types: "${method.returnType}" in API: "${api.name}" method: "${method.name}" (https://github.com/flutter/flutter/issues/87307)', - )); - } - if (method.arguments.any((NamedType arg) => - (arg.type.baseName == 'List' || arg.type.baseName == 'Map') && - arg.type.typeArguments.any( - (TypeDeclaration genericType) => isEnum(root, genericType)))) { - result.add(Error( - message: - 'Enums aren\'t yet supported for collection types: "${method.arguments[0]}" in API: "${api.name}" method: "${method.name}" (https://github.com/flutter/flutter/issues/87307)', - lineNumber: _calculateLineNumberNullable(source, method.offset), - )); - } for (final NamedType unnamedType in method.arguments .where((NamedType element) => element.type.baseName.isEmpty)) { result.add(Error( @@ -1594,14 +1568,16 @@ ${_argParser.usage}'''; if (options.objcHeaderOut != null) { options = options.merge(PigeonOptions( - objcOptions: options.objcOptions!.merge(ObjcOptions( - headerIncludePath: path.basename(options.objcHeaderOut!))))); + objcOptions: (options.objcOptions ?? const ObjcOptions()).merge( + ObjcOptions( + headerIncludePath: path.basename(options.objcHeaderOut!))))); } if (options.cppHeaderOut != null) { options = options.merge(PigeonOptions( - cppOptions: options.cppOptions!.merge(CppOptions( - headerIncludePath: path.basename(options.cppHeaderOut!))))); + cppOptions: (options.cppOptions ?? const CppOptions()).merge( + CppOptions( + headerIncludePath: path.basename(options.cppHeaderOut!))))); } for (final GeneratorAdapter adapter in safeGeneratorAdapters) { diff --git a/packages/pigeon/lib/swift_generator.dart b/packages/pigeon/lib/swift_generator.dart index e996a779b03..d382fffacb9 100644 --- a/packages/pigeon/lib/swift_generator.dart +++ b/packages/pigeon/lib/swift_generator.dart @@ -275,6 +275,18 @@ import FlutterMacOS required String dartPackageName, }) { assert(api.location == ApiLocation.flutter); + + /// Returns an argument name that can be used in a context where it is possible to collide. + String getEnumSafeArgumentExpression( + Root root, int count, NamedType argument) { + String enumTag = ''; + if (isEnum(root, argument.type)) { + enumTag = argument.type.isNullable ? '?.rawValue' : '.rawValue'; + } + + return '${_getArgumentName(count, argument)}Arg$enumTag'; + } + final bool isCustomCodec = getCodecClasses(api, root).isNotEmpty; if (isCustomCodec) { _writeCodec(indent, api, root); @@ -327,7 +339,12 @@ import FlutterMacOS }); final Iterable argNames = indexMap(func.arguments, _getSafeArgumentName); - sendArgument = '[${argNames.join(', ')}] as [Any?]'; + final Iterable enumSafeArgNames = func.arguments + .asMap() + .entries + .map((MapEntry e) => + getEnumSafeArgumentExpression(root, e.key, e.value)); + sendArgument = '[${enumSafeArgNames.join(', ')}] as [Any?]'; final String argsSignature = map3( argTypes, argLabels, @@ -503,9 +520,14 @@ import FlutterMacOS indent.addScoped('{ result in', '}', () { indent.write('switch result '); indent.addScoped('{', '}', () { + final String nullsafe = + method.returnType.isNullable ? '?' : ''; + final String enumTag = isEnum(root, method.returnType) + ? '$nullsafe.rawValue' + : ''; indent.writeln('case .success$successVariableInit:'); indent.nest(1, () { - indent.writeln('reply(wrapResult($resultName))'); + indent.writeln('reply(wrapResult($resultName$enumTag))'); }); indent.writeln('case .failure(let error):'); indent.nest(1, () { @@ -520,8 +542,16 @@ import FlutterMacOS indent.writeln(call); indent.writeln('reply(wrapResult(nil))'); } else { + String enumTag = ''; + if (isEnum(root, method.returnType)) { + enumTag = '.rawValue'; + } + enumTag = method.returnType.isNullable && + isEnum(root, method.returnType) + ? '?$enumTag' + : enumTag; indent.writeln('let result = $call'); - indent.writeln('reply(wrapResult(result))'); + indent.writeln('reply(wrapResult(result$enumTag))'); } }, addTrailingNewline: false); indent.addScoped(' catch {', '}', () { @@ -640,16 +670,19 @@ import FlutterMacOS }) { String castForceUnwrap(String value, TypeDeclaration type, Root root) { if (isEnum(root, type)) { - assert(!type.isNullable, - 'nullable enums require special code that this helper does not supply'); - return '${_swiftTypeForDartType(type)}(rawValue: $value as! Int)!'; + String output = + '${_swiftTypeForDartType(type)}(rawValue: $value as! Int)!'; + if (type.isNullable) { + output = 'isNullish($value) ? nil : $output'; + } + return output; } else 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 '$value is NSNull ? nil : ($value is Int64? ? $value as! Int64? : Int64($value as! Int32))'; + 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)'; } @@ -699,6 +732,14 @@ import FlutterMacOS } } + void _writeIsNullish(Indent indent) { + indent.newln(); + indent.write('private func isNullish(_ value: Any?) -> Bool '); + indent.addScoped('{', '}', () { + indent.writeln('return value is NSNull || value == nil'); + }); + } + void _writeWrapResult(Indent indent) { indent.newln(); indent.write('private func wrapResult(_ result: Any?) -> [Any?] '); @@ -745,6 +786,7 @@ private func nilOrValue(_ value: Any?) -> T? { Indent indent, { required String dartPackageName, }) { + _writeIsNullish(indent); _writeWrapResult(indent); _writeWrapError(indent); _writeNilOrValue(indent); diff --git a/packages/pigeon/pigeons/core_tests.dart b/packages/pigeon/pigeons/core_tests.dart index f590f87c046..ffe94ace2d3 100644 --- a/packages/pigeon/pigeons/core_tests.dart +++ b/packages/pigeon/pigeons/core_tests.dart @@ -166,6 +166,11 @@ abstract class HostIntegrationCoreApi { @SwiftFunction('echo(_:)') AllClassesWrapper echoClassWrapper(AllClassesWrapper wrapper); + /// Returns the passed enum to test serialization and deserialization. + @ObjCSelector('echoEnum:') + @SwiftFunction('echo(_:)') + AnEnum echoEnum(AnEnum anEnum); + // ========== Synchronous nullable method tests ========== /// Returns the passed object, to test serialization and deserialization. @@ -231,6 +236,10 @@ abstract class HostIntegrationCoreApi { @SwiftFunction('echoNullable(_:)') Map? echoNullableMap(Map? aNullableMap); + @ObjCSelector('echoNullableEnum:') + @SwiftFunction('echoNullable(_:)') + AnEnum? echoNullableEnum(AnEnum? anEnum); + // ========== Asynchronous method tests ========== /// A no-op function taking no arguments and returning no value, to sanity @@ -274,18 +283,24 @@ abstract class HostIntegrationCoreApi { @SwiftFunction('echoAsync(_:)') Object echoAsyncObject(Object anObject); - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. @async @ObjCSelector('echoAsyncList:') @SwiftFunction('echoAsync(_:)') List echoAsyncList(List aList); - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. @async @ObjCSelector('echoAsyncMap:') @SwiftFunction('echoAsync(_:)') Map echoAsyncMap(Map aMap); + /// Returns the passed enum, to test asynchronous serialization and deserialization. + @async + @ObjCSelector('echoAsyncEnum:') + @SwiftFunction('echoAsync(_:)') + AnEnum echoAsyncEnum(AnEnum anEnum); + /// Responds with an error from an async function returning a value. @async Object? throwAsyncError(); @@ -347,18 +362,24 @@ abstract class HostIntegrationCoreApi { @SwiftFunction('echoAsyncNullable(_:)') Object? echoAsyncNullableObject(Object? anObject); - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. @async @ObjCSelector('echoAsyncNullableList:') @SwiftFunction('echoAsyncNullable(_:)') List? echoAsyncNullableList(List? aList); - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. @async @ObjCSelector('echoAsyncNullableMap:') @SwiftFunction('echoAsyncNullable(_:)') Map? echoAsyncNullableMap(Map? aMap); + /// Returns the passed enum, to test asynchronous serialization and deserialization. + @async + @ObjCSelector('echoAsyncNullableEnum:') + @SwiftFunction('echoAsyncNullable(_:)') + AnEnum? echoAsyncNullableEnum(AnEnum? anEnum); + // ========== Flutter API test wrappers ========== @async @@ -375,10 +396,11 @@ abstract class HostIntegrationCoreApi { @SwiftFunction('callFlutterEcho(_:)') AllTypes callFlutterEchoAllTypes(AllTypes everything); - // TODO(stuartmorgan): Add callFlutterEchoAllNullableTypes and the associated - // test once either https://github.com/flutter/flutter/issues/116117 is fixed, - // or the problematic type is moved out of AllNullableTypes and into its own - // test, since the type mismatch breaks the second `encode` round. + @async + @ObjCSelector('callFlutterEchoAllNullableTypes:') + @SwiftFunction('callFlutterEcho(_:)') + AllNullableTypes? callFlutterEchoAllNullableTypes( + AllNullableTypes? everything); @async @ObjCSelector('callFlutterSendMultipleNullableTypesABool:anInt:aString:') @@ -421,6 +443,11 @@ abstract class HostIntegrationCoreApi { @SwiftFunction('callFlutterEcho(_:)') Map callFlutterEchoMap(Map aMap); + @async + @ObjCSelector('callFlutterEchoEnum:') + @SwiftFunction('callFlutterEcho(_:)') + AnEnum callFlutterEchoEnum(AnEnum anEnum); + @async @ObjCSelector('callFlutterEchoNullableBool:') @SwiftFunction('callFlutterEchoNullable(_:)') @@ -456,6 +483,11 @@ abstract class HostIntegrationCoreApi { @SwiftFunction('callFlutterEchoNullable(_:)') Map? callFlutterEchoNullableMap( Map? aMap); + + @async + @ObjCSelector('callFlutterEchoNullableEnum:') + @SwiftFunction('callFlutterNullableEcho(_:)') + AnEnum? callFlutterEchoNullableEnum(AnEnum? anEnum); } /// The core interface that the Dart platform_test code implements for host @@ -480,7 +512,7 @@ abstract class FlutterIntegrationCoreApi { /// Returns the passed object, to test serialization and deserialization. @ObjCSelector('echoAllNullableTypes:') @SwiftFunction('echoNullable(_:)') - AllNullableTypes echoAllNullableTypes(AllNullableTypes everything); + AllNullableTypes? echoAllNullableTypes(AllNullableTypes? everything); /// Returns passed in arguments of multiple types. /// @@ -527,6 +559,11 @@ abstract class FlutterIntegrationCoreApi { @SwiftFunction('echo(_:)') Map echoMap(Map aMap); + /// Returns the passed enum to test serialization and deserialization. + @ObjCSelector('echoEnum:') + @SwiftFunction('echo(_:)') + AnEnum echoEnum(AnEnum anEnum); + // ========== Nullable argument/return type tests ========== /// Returns the passed boolean, to test serialization and deserialization. @@ -564,6 +601,11 @@ abstract class FlutterIntegrationCoreApi { @SwiftFunction('echoNullable(_:)') Map? echoNullableMap(Map? aMap); + /// Returns the passed enum to test serialization and deserialization. + @ObjCSelector('echoNullableEnum:') + @SwiftFunction('echoNullable(_:)') + AnEnum? echoNullableEnum(AnEnum? anEnum); + // ========== Async tests ========== // These are minimal since async FlutterApi only changes Dart generation. // Currently they aren't integration tested, but having them here ensures diff --git a/packages/pigeon/pigeons/enum.dart b/packages/pigeon/pigeons/enum.dart index d15bb563ed7..7a39e0bea2c 100644 --- a/packages/pigeon/pigeons/enum.dart +++ b/packages/pigeon/pigeons/enum.dart @@ -4,6 +4,10 @@ import 'package:pigeon/pigeon.dart'; +@ConfigurePigeon(PigeonOptions( + objcOptions: ObjcOptions(prefix: 'PGN'), +)) + /// This comment is to test enum documentation comments. enum EnumState { /// This comment is to test enum member (Pending) documentation comments. diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java index c9c4406d688..08d1a93eaeb 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java @@ -9,6 +9,7 @@ import com.example.alternate_language_test_plugin.CoreTests.AllClassesWrapper; import com.example.alternate_language_test_plugin.CoreTests.AllNullableTypes; import com.example.alternate_language_test_plugin.CoreTests.AllTypes; +import com.example.alternate_language_test_plugin.CoreTests.AnEnum; import com.example.alternate_language_test_plugin.CoreTests.FlutterIntegrationCoreApi; import com.example.alternate_language_test_plugin.CoreTests.HostIntegrationCoreApi; import com.example.alternate_language_test_plugin.CoreTests.Result; @@ -99,11 +100,16 @@ public void throwErrorFromVoid() { return aMap; } - @NonNull - public AllClassesWrapper echoClassWrapper(@NonNull AllClassesWrapper wrapper) { + @Override + public @NonNull AllClassesWrapper echoClassWrapper(@NonNull AllClassesWrapper wrapper) { return wrapper; } + @Override + public @NonNull AnEnum echoEnum(@NonNull AnEnum anEnum) { + return anEnum; + } + @Override public @Nullable String extractNestedNullableString(@NonNull AllClassesWrapper wrapper) { return wrapper.getAllNullableTypes().getANullableString(); @@ -170,6 +176,11 @@ public AllClassesWrapper echoClassWrapper(@NonNull AllClassesWrapper wrapper) { return aNullableMap; } + @Override + public @Nullable AnEnum echoNullableEnum(@Nullable AnEnum anEnum) { + return anEnum; + } + @Override public void noopAsync(@NonNull Result result) { result.success(null); @@ -242,6 +253,11 @@ public void echoAsyncMap( result.success(aMap); } + @Override + public void echoAsyncEnum(@NonNull AnEnum anEnum, @NonNull Result result) { + result.success(anEnum); + } + @Override public void echoAsyncNullableInt(@Nullable Long anInt, @NonNull Result result) { result.success(anInt); @@ -285,6 +301,11 @@ public void echoAsyncNullableMap( result.success(aMap); } + @Override + public void echoAsyncNullableEnum(@Nullable AnEnum anEnum, @NonNull Result result) { + result.success(anEnum); + } + @Override public void callFlutterNoop(@NonNull Result result) { flutterApi.noop( @@ -331,6 +352,18 @@ public void reply(AllTypes value) { }); } + @Override + public void callFlutterEchoAllNullableTypes( + @Nullable AllNullableTypes everything, @NonNull Result result) { + flutterApi.echoAllNullableTypes( + everything, + new FlutterIntegrationCoreApi.Reply() { + public void reply(AllNullableTypes value) { + result.success(value); + } + }); + } + @Override public void callFlutterSendMultipleNullableTypes( @Nullable Boolean aNullableBool, @@ -427,6 +460,17 @@ public void reply(Map value) { }); } + @Override + public void callFlutterEchoEnum(@NonNull AnEnum anEnum, @NonNull Result result) { + flutterApi.echoEnum( + anEnum, + new FlutterIntegrationCoreApi.Reply() { + public void reply(AnEnum value) { + result.success(value); + } + }); + } + @Override public void callFlutterEchoNullableBool( @Nullable Boolean aBool, @NonNull Result result) { @@ -509,4 +553,15 @@ public void reply(Map value) { } }); } + + @Override + public void callFlutterEchoNullableEnum(@Nullable AnEnum anEnum, @NonNull Result result) { + flutterApi.echoNullableEnum( + anEnum, + new FlutterIntegrationCoreApi.Reply() { + public void reply(AnEnum value) { + result.success(value); + } + }); + } } diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java index 6f2215f91d6..fd32aad89be 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java @@ -407,7 +407,7 @@ ArrayList toList() { Object aMap = list.get(9); pigeonResult.setAMap((Map) aMap); Object anEnum = list.get(10); - pigeonResult.setAnEnum(anEnum == null ? null : AnEnum.values()[(int) anEnum]); + pigeonResult.setAnEnum(AnEnum.values()[(int) anEnum]); Object aString = list.get(11); pigeonResult.setAString((String) aString); Object anObject = list.get(12); @@ -1014,6 +1014,9 @@ public interface HostIntegrationCoreApi { /** Returns the passed map to test nested class serialization and deserialization. */ @NonNull AllClassesWrapper echoClassWrapper(@NonNull AllClassesWrapper wrapper); + /** Returns the passed enum to test serialization and deserialization. */ + @NonNull + AnEnum echoEnum(@NonNull AnEnum anEnum); /** Returns the passed object, to test serialization and deserialization. */ @Nullable AllNullableTypes echoAllNullableTypes(@Nullable AllNullableTypes everything); @@ -1057,6 +1060,9 @@ AllNullableTypes sendMultipleNullableTypes( /** Returns the passed map, to test serialization and deserialization. */ @Nullable Map echoNullableMap(@Nullable Map aNullableMap); + + @Nullable + AnEnum echoNullableEnum(@Nullable AnEnum anEnum); /** * A no-op function taking no arguments and returning no value, to sanity test basic * asynchronous calling. @@ -1074,11 +1080,13 @@ AllNullableTypes sendMultipleNullableTypes( void echoAsyncUint8List(@NonNull byte[] aUint8List, @NonNull Result result); /** Returns the passed in generic Object asynchronously. */ void echoAsyncObject(@NonNull Object anObject, @NonNull Result result); - /** Returns the passed list, to test serialization and deserialization asynchronously. */ + /** Returns the passed list, to test asynchronous serialization and deserialization. */ void echoAsyncList(@NonNull List aList, @NonNull Result> result); - /** Returns the passed map, to test serialization and deserialization asynchronously. */ + /** Returns the passed map, to test asynchronous serialization and deserialization. */ void echoAsyncMap( @NonNull Map aMap, @NonNull Result> result); + /** Returns the passed enum, to test asynchronous serialization and deserialization. */ + void echoAsyncEnum(@NonNull AnEnum anEnum, @NonNull Result result); /** Responds with an error from an async function returning a value. */ void throwAsyncError(@NonNull Result result); /** Responds with an error from an async void function. */ @@ -1102,11 +1110,13 @@ void echoAsyncNullableAllNullableTypes( void echoAsyncNullableUint8List(@Nullable byte[] aUint8List, @NonNull Result result); /** Returns the passed in generic Object asynchronously. */ void echoAsyncNullableObject(@Nullable Object anObject, @NonNull Result result); - /** Returns the passed list, to test serialization and deserialization asynchronously. */ + /** Returns the passed list, to test asynchronous serialization and deserialization. */ void echoAsyncNullableList(@Nullable List aList, @NonNull Result> result); - /** Returns the passed map, to test serialization and deserialization asynchronously. */ + /** Returns the passed map, to test asynchronous serialization and deserialization. */ void echoAsyncNullableMap( @Nullable Map aMap, @NonNull Result> result); + /** Returns the passed enum, to test asynchronous serialization and deserialization. */ + void echoAsyncNullableEnum(@Nullable AnEnum anEnum, @NonNull Result result); void callFlutterNoop(@NonNull Result result); @@ -1116,6 +1126,9 @@ void echoAsyncNullableMap( void callFlutterEchoAllTypes(@NonNull AllTypes everything, @NonNull Result result); + void callFlutterEchoAllNullableTypes( + @Nullable AllNullableTypes everything, @NonNull Result result); + void callFlutterSendMultipleNullableTypes( @Nullable Boolean aNullableBool, @Nullable Long aNullableInt, @@ -1137,6 +1150,8 @@ void callFlutterSendMultipleNullableTypes( void callFlutterEchoMap( @NonNull Map aMap, @NonNull Result> result); + void callFlutterEchoEnum(@NonNull AnEnum anEnum, @NonNull Result result); + void callFlutterEchoNullableBool(@Nullable Boolean aBool, @NonNull Result result); void callFlutterEchoNullableInt(@Nullable Long anInt, @NonNull Result result); @@ -1153,6 +1168,8 @@ void callFlutterEchoNullableList( void callFlutterEchoNullableMap( @Nullable Map aMap, @NonNull Result> result); + void callFlutterEchoNullableEnum(@Nullable AnEnum anEnum, @NonNull Result result); + /** The codec used by HostIntegrationCoreApi. */ static @NonNull MessageCodec getCodec() { return HostIntegrationCoreApiCodec.INSTANCE; @@ -1505,6 +1522,31 @@ static void setup( channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoEnum", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + AnEnum anEnumArg = AnEnum.values()[(int) args.get(0)]; + try { + AnEnum output = api.echoEnum(anEnumArg); + wrapped.add(0, output.index); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( @@ -1813,6 +1855,31 @@ static void setup( channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoNullableEnum", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + AnEnum anEnumArg = args.get(0) == null ? null : AnEnum.values()[(int) args.get(0)]; + try { + AnEnum output = api.echoNullableEnum(anEnumArg); + wrapped.add(0, output == null ? null : output.index); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( @@ -2090,6 +2157,37 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncEnum", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + AnEnum anEnumArg = AnEnum.values()[(int) args.get(0)]; + Result resultCallback = + new Result() { + public void success(AnEnum result) { + wrapped.add(0, result.index); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.echoAsyncEnum(anEnumArg, resultCallback); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( @@ -2488,6 +2586,37 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncNullableEnum", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + AnEnum anEnumArg = args.get(0) == null ? null : AnEnum.values()[(int) args.get(0)]; + Result resultCallback = + new Result() { + public void success(AnEnum result) { + wrapped.add(0, result == null ? null : result.index); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.echoAsyncNullableEnum(anEnumArg, resultCallback); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( @@ -2606,6 +2735,37 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoAllNullableTypes", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + AllNullableTypes everythingArg = (AllNullableTypes) args.get(0); + Result resultCallback = + new Result() { + public void success(AllNullableTypes result) { + wrapped.add(0, result); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.callFlutterEchoAllNullableTypes(everythingArg, resultCallback); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( @@ -2861,6 +3021,37 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoEnum", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + AnEnum anEnumArg = AnEnum.values()[(int) args.get(0)]; + Result resultCallback = + new Result() { + public void success(AnEnum result) { + wrapped.add(0, result.index); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.callFlutterEchoEnum(anEnumArg, resultCallback); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( @@ -3079,6 +3270,37 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoNullableEnum", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + AnEnum anEnumArg = args.get(0) == null ? null : AnEnum.values()[(int) args.get(0)]; + Result resultCallback = + new Result() { + public void success(AnEnum result) { + wrapped.add(0, result == null ? null : result.index); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.callFlutterEchoNullableEnum(anEnumArg, resultCallback); + }); + } else { + channel.setMessageHandler(null); + } + } } } @@ -3198,7 +3420,7 @@ public void echoAllTypes(@NonNull AllTypes everythingArg, @NonNull Reply callback) { + @Nullable AllNullableTypes everythingArg, @NonNull Reply callback) { BasicMessageChannel channel = new BasicMessageChannel<>( binaryMessenger, @@ -3342,6 +3564,21 @@ public void echoMap( callback.reply(output); }); } + /** Returns the passed enum to test serialization and deserialization. */ + public void echoEnum(@NonNull AnEnum anEnumArg, @NonNull Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoEnum", + getCodec()); + channel.send( + new ArrayList(Collections.singletonList(anEnumArg.index)), + channelReply -> { + @SuppressWarnings("ConstantConditions") + AnEnum output = AnEnum.values()[(int) channelReply]; + callback.reply(output); + }); + } /** Returns the passed boolean, to test serialization and deserialization. */ public void echoNullableBool(@Nullable Boolean aBoolArg, @NonNull Reply callback) { BasicMessageChannel channel = @@ -3449,6 +3686,22 @@ public void echoNullableMap( callback.reply(output); }); } + /** Returns the passed enum to test serialization and deserialization. */ + public void echoNullableEnum(@Nullable AnEnum anEnumArg, @NonNull Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoNullableEnum", + getCodec()); + channel.send( + new ArrayList( + Collections.singletonList(anEnumArg == null ? null : anEnumArg.index)), + channelReply -> { + @SuppressWarnings("ConstantConditions") + AnEnum output = channelReply == null ? null : AnEnum.values()[(int) channelReply]; + callback.reply(output); + }); + } /** * A no-op function taking no arguments and returning no value, to sanity test basic * asynchronous calling. diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/EnumTest.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/EnumTest.m index 99ff3eb4a11..7a3350ee9e0 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/EnumTest.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/EnumTest.m @@ -17,15 +17,16 @@ @interface EnumTest : XCTestCase @implementation EnumTest - (void)testEcho { - DataWithEnum *data = [[DataWithEnum alloc] init]; - data.state = EnumStateError; + PGNDataWithEnum *data = [[PGNDataWithEnum alloc] init]; + PGNEnumStateBox *stateBox = [[PGNEnumStateBox alloc] initWithValue:PGNEnumStateError]; + data.state = stateBox; EchoBinaryMessenger *binaryMessenger = - [[EchoBinaryMessenger alloc] initWithCodec:EnumApi2HostGetCodec()]; - EnumApi2Flutter *api = [[EnumApi2Flutter alloc] initWithBinaryMessenger:binaryMessenger]; + [[EchoBinaryMessenger alloc] initWithCodec:PGNEnumApi2HostGetCodec()]; + PGNEnumApi2Flutter *api = [[PGNEnumApi2Flutter alloc] initWithBinaryMessenger:binaryMessenger]; XCTestExpectation *expectation = [self expectationWithDescription:@"callback"]; [api echoData:data - completion:^(DataWithEnum *_Nonnull result, FlutterError *_Nullable error) { - XCTAssertEqual(data.state, result.state); + completion:^(PGNDataWithEnum *_Nonnull result, FlutterError *_Nullable error) { + XCTAssertEqual(data.state.value, result.state.value); [expectation fulfill]; }]; [self waitForExpectations:@[ expectation ] timeout:1.0]; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/NullFieldsTest.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/NullFieldsTest.m index 605f15febfb..04f9c7d3d1b 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/NullFieldsTest.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/NullFieldsTest.m @@ -31,19 +31,20 @@ @implementation NullFieldsTest - (void)testMakeWithValues { NullFieldsSearchRequest *request = [NullFieldsSearchRequest makeWithQuery:@"hello" identifier:@1]; - NullFieldsSearchReply *reply = - [NullFieldsSearchReply makeWithResult:@"result" - error:@"error" - indices:@[ @1, @2, @3 ] - request:request - type:NullFieldsSearchReplyTypeSuccess]; + NullFieldsSearchReplyTypeBox *typeWrapper = + [[NullFieldsSearchReplyTypeBox alloc] initWithValue:NullFieldsSearchReplyTypeSuccess]; + NullFieldsSearchReply *reply = [NullFieldsSearchReply makeWithResult:@"result" + error:@"error" + indices:@[ @1, @2, @3 ] + request:request + type:typeWrapper]; NSArray *indices = @[ @1, @2, @3 ]; XCTAssertEqualObjects(@"result", reply.result); XCTAssertEqualObjects(@"error", reply.error); XCTAssertEqualObjects(indices, reply.indices); XCTAssertEqualObjects(@"hello", reply.request.query); - XCTAssertEqual(NullFieldsSearchReplyTypeSuccess, reply.type); + XCTAssertEqual(typeWrapper.value, reply.type.value); } - (void)testMakeRequestWithNulls { @@ -52,17 +53,16 @@ - (void)testMakeRequestWithNulls { } - (void)testMakeReplyWithNulls { - NullFieldsSearchReply *reply = - [NullFieldsSearchReply makeWithResult:nil - error:nil - indices:nil - request:nil - type:NullFieldsSearchReplyTypeSuccess]; + NullFieldsSearchReply *reply = [NullFieldsSearchReply makeWithResult:nil + error:nil + indices:nil + request:nil + type:nil]; XCTAssertNil(reply.result); XCTAssertNil(reply.error); XCTAssertNil(reply.indices); XCTAssertNil(reply.request); - XCTAssertEqual(NullFieldsSearchReplyTypeSuccess, reply.type); + XCTAssertNil(reply.type); } - (void)testRequestFromListWithValues { @@ -101,7 +101,7 @@ - (void)testReplyFromListWithValues { XCTAssertEqualObjects(@"error", reply.error); XCTAssertEqualObjects(indices, reply.indices); XCTAssertEqualObjects(@"hello", reply.request.query); - XCTAssertEqual(NullFieldsSearchReplyTypeSuccess, reply.type); + XCTAssertEqual(NullFieldsSearchReplyTypeSuccess, reply.type.value); } - (void)testReplyFromListWithNulls { @@ -117,7 +117,7 @@ - (void)testReplyFromListWithNulls { XCTAssertNil(reply.error); XCTAssertNil(reply.indices); XCTAssertNil(reply.request.query); - XCTAssertEqual(NullFieldsSearchReplyTypeSuccess, reply.type); + XCTAssertNil(reply.type); } - (void)testRequestToListWithValuess { @@ -133,33 +133,39 @@ - (void)testRequestToListWithNulls { } - (void)testReplyToListWithValuess { + NullFieldsSearchReplyTypeBox *typeWrapper = + [[NullFieldsSearchReplyTypeBox alloc] initWithValue:NullFieldsSearchReplyTypeSuccess]; NullFieldsSearchReply *reply = [NullFieldsSearchReply makeWithResult:@"result" error:@"error" indices:@[ @1, @2, @3 ] request:[NullFieldsSearchRequest makeWithQuery:@"hello" identifier:@1] - type:NullFieldsSearchReplyTypeSuccess]; + type:typeWrapper]; NSArray *list = [reply toList]; NSArray *indices = @[ @1, @2, @3 ]; XCTAssertEqualObjects(@"result", list[0]); XCTAssertEqualObjects(@"error", list[1]); XCTAssertEqualObjects(indices, list[2]); XCTAssertEqualObjects(@"hello", list[3][0]); - XCTAssertEqualObjects(@0, list[4]); + NSNumber *typeNumber = list[4]; + NullFieldsSearchReplyTypeBox *output = + [[NullFieldsSearchReplyTypeBox alloc] initWithValue:[typeNumber integerValue]]; + + XCTAssertEqual(typeWrapper.value, output.value); } - (void)testReplyToListWithNulls { - NullFieldsSearchReply *reply = - [NullFieldsSearchReply makeWithResult:nil - error:nil - indices:nil - request:nil - type:NullFieldsSearchReplyTypeSuccess]; + NullFieldsSearchReply *reply = [NullFieldsSearchReply makeWithResult:nil + error:nil + indices:nil + request:nil + type:nil]; NSArray *list = [reply toList]; XCTAssertEqual([NSNull null], list[0]); XCTAssertEqual([NSNull null], list[1]); XCTAssertEqual([NSNull null], list[2]); XCTAssertEqual([NSNull null], list[3]); + XCTAssertEqual([NSNull null], list[4]); } @end diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/AlternateLanguageTestPlugin.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/AlternateLanguageTestPlugin.m index 1df7a345754..3423d53f5e0 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/AlternateLanguageTestPlugin.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/AlternateLanguageTestPlugin.m @@ -92,6 +92,10 @@ - (nullable AllClassesWrapper *)echoClassWrapper:(AllClassesWrapper *)wrapper return wrapper; } +- (AnEnum)echoEnum:(AnEnum)anEnum error:(FlutterError *_Nullable *_Nonnull)error { + return anEnum; +} + - (nullable NSString *)extractNestedNullableStringFrom:(AllClassesWrapper *)wrapper error:(FlutterError *_Nullable *_Nonnull)error { return wrapper.allNullableTypes.aNullableString; @@ -159,6 +163,11 @@ - (nullable id)echoNullableObject:(nullable id)aNullableObject return aNullableMap; } +- (AnEnumBox *_Nullable)echoNullableEnum:(nullable AnEnumBox *)AnEnumBoxed + error:(FlutterError *_Nullable *_Nonnull)error { + return AnEnumBoxed; +} + - (void)noopAsyncWithCompletion:(void (^)(FlutterError *_Nullable))completion { completion(nil); } @@ -229,6 +238,11 @@ - (void)echoAsyncMap:(NSDictionary *)aMap completion(aMap, nil); } +- (void)echoAsyncEnum:(AnEnum)anEnum + completion:(void (^)(AnEnum, FlutterError *_Nullable))completion { + completion(anEnum, nil); +} + - (void)echoAsyncNullableInt:(nullable NSNumber *)anInt completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion { completion(anInt, nil); @@ -272,6 +286,11 @@ - (void)echoAsyncNullableMap:(nullable NSDictionary *)aMap completion(aMap, nil); } +- (void)echoAsyncNullableEnum:(nullable AnEnumBox *)AnEnumBoxed + completion:(void (^)(AnEnumBox *_Nullable, FlutterError *_Nullable))completion { + completion(AnEnumBoxed, nil); +} + - (void)callFlutterNoopWithCompletion:(void (^)(FlutterError *_Nullable))completion { [self.flutterAPI noopWithCompletion:^(FlutterError *error) { completion(error); @@ -370,6 +389,23 @@ - (void)callFlutterEchoMap:(NSDictionary *)aMap }]; } +- (void)callFlutterEchoEnum:(AnEnum)anEnum + completion:(void (^)(AnEnum, FlutterError *_Nullable))completion { + [self.flutterAPI echoEnum:anEnum + completion:^(AnEnum value, FlutterError *error) { + completion(value, error); + }]; +} + +- (void)callFlutterEchoAllNullableTypes:(nullable AllNullableTypes *)everything + completion:(void (^)(AllNullableTypes *_Nullable, + FlutterError *_Nullable))completion { + [self.flutterAPI echoAllNullableTypes:everything + completion:^(AllNullableTypes *value, FlutterError *error) { + completion(value, error); + }]; +} + - (void)callFlutterEchoNullableBool:(nullable NSNumber *)aBool completion: (void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion { @@ -433,4 +469,13 @@ - (void)callFlutterEchoNullableMap:(nullable NSDictionary *)aMap }]; } +- (void)callFlutterEchoNullableEnum:(nullable AnEnumBox *)AnEnumBoxed + completion: + (void (^)(AnEnumBox *_Nullable, FlutterError *_Nullable))completion { + [self.flutterAPI echoNullableEnum:AnEnumBoxed + completion:^(AnEnumBox *value, FlutterError *error) { + completion(value, error); + }]; +} + @end diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h index 2cf2d11b4d8..1b558e4f6a8 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h @@ -20,6 +20,12 @@ typedef NS_ENUM(NSUInteger, AnEnum) { AnEnumThree = 2, }; +/// Wrapper for AnEnum to allow for nullability. +@interface AnEnumBox : NSObject +@property(nonatomic, assign) AnEnum value; +- (instancetype)initWithValue:(AnEnum)value; +@end + @class AllTypes; @class AllNullableTypes; @class AllClassesWrapper; @@ -73,9 +79,9 @@ typedef NS_ENUM(NSUInteger, AnEnum) { nullableMapWithAnnotations: (nullable NSDictionary *)nullableMapWithAnnotations nullableMapWithObject:(nullable NSDictionary *)nullableMapWithObject - aNullableEnum:(AnEnum)aNullableEnum + aNullableEnum:(nullable AnEnumBox *)aNullableEnum aNullableString:(nullable NSString *)aNullableString - aNullableObject:(id)aNullableObject; + aNullableObject:(nullable id)aNullableObject; @property(nonatomic, strong, nullable) NSNumber *aNullableBool; @property(nonatomic, strong, nullable) NSNumber *aNullableInt; @property(nonatomic, strong, nullable) NSNumber *aNullableInt64; @@ -90,9 +96,9 @@ typedef NS_ENUM(NSUInteger, AnEnum) { @property(nonatomic, strong, nullable) NSDictionary *nullableMapWithAnnotations; @property(nonatomic, strong, nullable) NSDictionary *nullableMapWithObject; -@property(nonatomic, assign) AnEnum aNullableEnum; +@property(nonatomic, strong, nullable) AnEnumBox *aNullableEnum; @property(nonatomic, copy, nullable) NSString *aNullableString; -@property(nonatomic, strong) id aNullableObject; +@property(nonatomic, strong, nullable) id aNullableObject; @end /// A class for testing nested class handling. @@ -177,6 +183,10 @@ NSObject *HostIntegrationCoreApiGetCodec(void); /// @return `nil` only when `error != nil`. - (nullable AllClassesWrapper *)echoClassWrapper:(AllClassesWrapper *)wrapper error:(FlutterError *_Nullable *_Nonnull)error; +/// Returns the passed enum to test serialization and deserialization. +/// +/// @return `nil` only when `error != nil`. +- (AnEnum)echoEnum:(AnEnum)anEnum error:(FlutterError *_Nullable *_Nonnull)error; /// Returns the passed object, to test serialization and deserialization. - (nullable AllNullableTypes *)echoAllNullableTypes:(nullable AllNullableTypes *)everything error:(FlutterError *_Nullable *_Nonnull)error; @@ -225,6 +235,8 @@ NSObject *HostIntegrationCoreApiGetCodec(void); - (nullable NSDictionary *)echoNullableMap: (nullable NSDictionary *)aNullableMap error:(FlutterError *_Nullable *_Nonnull)error; +- (AnEnumBox *_Nullable)echoNullableEnum:(nullable AnEnumBox *)anEnumBoxed + error:(FlutterError *_Nullable *_Nonnull)error; /// A no-op function taking no arguments and returning no value, to sanity /// test basic asynchronous calling. - (void)noopAsyncWithCompletion:(void (^)(FlutterError *_Nullable))completion; @@ -247,13 +259,16 @@ NSObject *HostIntegrationCoreApiGetCodec(void); /// Returns the passed in generic Object asynchronously. - (void)echoAsyncObject:(id)anObject completion:(void (^)(id _Nullable, FlutterError *_Nullable))completion; -/// Returns the passed list, to test serialization and deserialization asynchronously. +/// Returns the passed list, to test asynchronous serialization and deserialization. - (void)echoAsyncList:(NSArray *)aList completion:(void (^)(NSArray *_Nullable, FlutterError *_Nullable))completion; -/// Returns the passed map, to test serialization and deserialization asynchronously. +/// Returns the passed map, to test asynchronous serialization and deserialization. - (void)echoAsyncMap:(NSDictionary *)aMap completion:(void (^)(NSDictionary *_Nullable, FlutterError *_Nullable))completion; +/// Returns the passed enum, to test asynchronous serialization and deserialization. +- (void)echoAsyncEnum:(AnEnum)anEnum + completion:(void (^)(AnEnum, FlutterError *_Nullable))completion; /// Responds with an error from an async function returning a value. - (void)throwAsyncErrorWithCompletion:(void (^)(id _Nullable, FlutterError *_Nullable))completion; /// Responds with an error from an async void function. @@ -287,19 +302,25 @@ NSObject *HostIntegrationCoreApiGetCodec(void); /// Returns the passed in generic Object asynchronously. - (void)echoAsyncNullableObject:(nullable id)anObject completion:(void (^)(id _Nullable, FlutterError *_Nullable))completion; -/// Returns the passed list, to test serialization and deserialization asynchronously. +/// Returns the passed list, to test asynchronous serialization and deserialization. - (void)echoAsyncNullableList:(nullable NSArray *)aList completion:(void (^)(NSArray *_Nullable, FlutterError *_Nullable))completion; -/// Returns the passed map, to test serialization and deserialization asynchronously. +/// Returns the passed map, to test asynchronous serialization and deserialization. - (void)echoAsyncNullableMap:(nullable NSDictionary *)aMap completion:(void (^)(NSDictionary *_Nullable, FlutterError *_Nullable))completion; +/// Returns the passed enum, to test asynchronous serialization and deserialization. +- (void)echoAsyncNullableEnum:(nullable AnEnumBox *)anEnumBoxed + completion:(void (^)(AnEnumBox *_Nullable, FlutterError *_Nullable))completion; - (void)callFlutterNoopWithCompletion:(void (^)(FlutterError *_Nullable))completion; - (void)callFlutterThrowErrorWithCompletion:(void (^)(id _Nullable, FlutterError *_Nullable))completion; - (void)callFlutterThrowErrorFromVoidWithCompletion:(void (^)(FlutterError *_Nullable))completion; - (void)callFlutterEchoAllTypes:(AllTypes *)everything completion:(void (^)(AllTypes *_Nullable, FlutterError *_Nullable))completion; +- (void)callFlutterEchoAllNullableTypes:(nullable AllNullableTypes *)everything + completion:(void (^)(AllNullableTypes *_Nullable, + FlutterError *_Nullable))completion; - (void)callFlutterSendMultipleNullableTypesABool:(nullable NSNumber *)aNullableBool anInt:(nullable NSNumber *)aNullableInt aString:(nullable NSString *)aNullableString @@ -321,6 +342,8 @@ NSObject *HostIntegrationCoreApiGetCodec(void); - (void)callFlutterEchoMap:(NSDictionary *)aMap completion:(void (^)(NSDictionary *_Nullable, FlutterError *_Nullable))completion; +- (void)callFlutterEchoEnum:(AnEnum)anEnum + completion:(void (^)(AnEnum, FlutterError *_Nullable))completion; - (void)callFlutterEchoNullableBool:(nullable NSNumber *)aBool completion: (void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; @@ -342,6 +365,9 @@ NSObject *HostIntegrationCoreApiGetCodec(void); - (void)callFlutterEchoNullableMap:(nullable NSDictionary *)aMap completion:(void (^)(NSDictionary *_Nullable, FlutterError *_Nullable))completion; +- (void)callFlutterEchoNullableEnum:(nullable AnEnumBox *)anEnumBoxed + completion: + (void (^)(AnEnumBox *_Nullable, FlutterError *_Nullable))completion; @end extern void HostIntegrationCoreApiSetup(id binaryMessenger, @@ -365,7 +391,7 @@ NSObject *FlutterIntegrationCoreApiGetCodec(void); - (void)echoAllTypes:(AllTypes *)everything completion:(void (^)(AllTypes *_Nullable, FlutterError *_Nullable))completion; /// Returns the passed object, to test serialization and deserialization. -- (void)echoAllNullableTypes:(AllNullableTypes *)everything +- (void)echoAllNullableTypes:(nullable AllNullableTypes *)everything completion: (void (^)(AllNullableTypes *_Nullable, FlutterError *_Nullable))completion; /// Returns passed in arguments of multiple types. @@ -399,6 +425,8 @@ NSObject *FlutterIntegrationCoreApiGetCodec(void); - (void)echoMap:(NSDictionary *)aMap completion: (void (^)(NSDictionary *_Nullable, FlutterError *_Nullable))completion; +/// Returns the passed enum to test serialization and deserialization. +- (void)echoEnum:(AnEnum)anEnum completion:(void (^)(AnEnum, FlutterError *_Nullable))completion; /// Returns the passed boolean, to test serialization and deserialization. - (void)echoNullableBool:(nullable NSNumber *)aBool completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; @@ -422,6 +450,9 @@ NSObject *FlutterIntegrationCoreApiGetCodec(void); - (void)echoNullableMap:(nullable NSDictionary *)aMap completion:(void (^)(NSDictionary *_Nullable, FlutterError *_Nullable))completion; +/// Returns the passed enum to test serialization and deserialization. +- (void)echoNullableEnum:(nullable AnEnumBox *)anEnumBoxed + completion:(void (^)(AnEnumBox *_Nullable, FlutterError *_Nullable))completion; /// A no-op function taking no arguments and returning no value, to sanity /// test basic asynchronous calling. - (void)noopAsyncWithCompletion:(void (^)(FlutterError *_Nullable))completion; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m index 524a9dd7037..f68ecd87931 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m @@ -17,6 +17,16 @@ #error File requires ARC to be enabled. #endif +@implementation AnEnumBox +- (instancetype)initWithValue:(AnEnum)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + static NSArray *wrapResult(id result, FlutterError *error) { if (error) { return @[ @@ -150,9 +160,9 @@ + (instancetype)makeWithANullableBool:(nullable NSNumber *)aNullableBool nullableMapWithAnnotations: (nullable NSDictionary *)nullableMapWithAnnotations nullableMapWithObject:(nullable NSDictionary *)nullableMapWithObject - aNullableEnum:(AnEnum)aNullableEnum + aNullableEnum:(nullable AnEnumBox *)aNullableEnum aNullableString:(nullable NSString *)aNullableString - aNullableObject:(id)aNullableObject { + aNullableObject:(nullable id)aNullableObject { AllNullableTypes *pigeonResult = [[AllNullableTypes alloc] init]; pigeonResult.aNullableBool = aNullableBool; pigeonResult.aNullableInt = aNullableInt; @@ -187,7 +197,12 @@ + (AllNullableTypes *)fromList:(NSArray *)list { pigeonResult.nullableNestedList = GetNullableObjectAtIndex(list, 10); pigeonResult.nullableMapWithAnnotations = GetNullableObjectAtIndex(list, 11); pigeonResult.nullableMapWithObject = GetNullableObjectAtIndex(list, 12); - pigeonResult.aNullableEnum = [GetNullableObjectAtIndex(list, 13) integerValue]; + NSNumber *aNullableEnumAsNumber = GetNullableObjectAtIndex(list, 13); + AnEnumBox *aNullableEnum = + aNullableEnumAsNumber == nil + ? nil + : [[AnEnumBox alloc] initWithValue:[aNullableEnumAsNumber integerValue]]; + pigeonResult.aNullableEnum = aNullableEnum; pigeonResult.aNullableString = GetNullableObjectAtIndex(list, 14); pigeonResult.aNullableObject = GetNullableObjectAtIndex(list, 15); return pigeonResult; @@ -210,7 +225,8 @@ - (NSArray *)toList { (self.nullableNestedList ?: [NSNull null]), (self.nullableMapWithAnnotations ?: [NSNull null]), (self.nullableMapWithObject ?: [NSNull null]), - @(self.aNullableEnum), + (self.aNullableEnum == nil ? [NSNull null] + : [NSNumber numberWithInteger:self.aNullableEnum.value]), (self.aNullableString ?: [NSNull null]), (self.aNullableObject ?: [NSNull null]), ]; @@ -636,6 +652,29 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + /// Returns the passed enum to test serialization and deserialization. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName: + @"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoEnum" + binaryMessenger:binaryMessenger + codec:HostIntegrationCoreApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(echoEnum:error:)], + @"HostIntegrationCoreApi api (%@) doesn't respond to @selector(echoEnum:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + AnEnum arg_anEnum = [GetNullableObjectAtIndex(args, 0) integerValue]; + FlutterError *error; + AnEnum enumValue = [api echoEnum:arg_anEnum error:&error]; + NSNumber *output = [NSNumber numberWithInteger:enumValue]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } /// Returns the passed object, to test serialization and deserialization. { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] @@ -922,6 +961,33 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + @"echoNullableEnum" + binaryMessenger:binaryMessenger + codec:HostIntegrationCoreApiGetCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(echoNullableEnum:error:)], + @"HostIntegrationCoreApi api (%@) doesn't respond to @selector(echoNullableEnum:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSNumber *arg_anEnumAsNumber = GetNullableObjectAtIndex(args, 0); + AnEnumBox *arg_anEnum = + arg_anEnumAsNumber == nil + ? nil + : [[AnEnumBox alloc] initWithValue:[arg_anEnumAsNumber integerValue]]; + FlutterError *error; + AnEnumBox *enumBox = [api echoNullableEnum:arg_anEnum error:&error]; + NSNumber *output = enumBox == nil ? nil : [NSNumber numberWithInteger:enumBox.value]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } /// A no-op function taking no arguments and returning no value, to sanity /// test basic asynchronous calling. { @@ -1089,7 +1155,7 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName: @@ -1113,7 +1179,7 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName: @@ -1138,6 +1204,31 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + /// Returns the passed enum, to test asynchronous serialization and deserialization. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName: + @"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncEnum" + binaryMessenger:binaryMessenger + codec:HostIntegrationCoreApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(echoAsyncEnum:completion:)], + @"HostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(echoAsyncEnum:completion:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + AnEnum arg_anEnum = [GetNullableObjectAtIndex(args, 0) integerValue]; + [api echoAsyncEnum:arg_anEnum + completion:^(AnEnum enumValue, FlutterError *_Nullable error) { + NSNumber *output = [NSNumber numberWithInteger:enumValue]; + callback(wrapResult(output, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } /// Responds with an error from an async function returning a value. { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] @@ -1396,7 +1487,7 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." @@ -1420,7 +1511,7 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." @@ -1445,6 +1536,37 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + /// Returns the passed enum, to test asynchronous serialization and deserialization. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + @"echoAsyncNullableEnum" + binaryMessenger:binaryMessenger + codec:HostIntegrationCoreApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(echoAsyncNullableEnum:completion:)], + @"HostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(echoAsyncNullableEnum:completion:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSNumber *arg_anEnumAsNumber = GetNullableObjectAtIndex(args, 0); + AnEnumBox *arg_anEnum = + arg_anEnumAsNumber == nil + ? nil + : [[AnEnumBox alloc] initWithValue:[arg_anEnumAsNumber integerValue]]; + [api + echoAsyncNullableEnum:arg_anEnum + completion:^(AnEnumBox *_Nullable enumValue, FlutterError *_Nullable error) { + NSNumber *output = + enumValue == nil ? nil : [NSNumber numberWithInteger:enumValue.value]; + callback(wrapResult(output, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName: @@ -1529,6 +1651,30 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + @"callFlutterEchoAllNullableTypes" + binaryMessenger:binaryMessenger + codec:HostIntegrationCoreApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(callFlutterEchoAllNullableTypes:completion:)], + @"HostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(callFlutterEchoAllNullableTypes:completion:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + AllNullableTypes *arg_everything = GetNullableObjectAtIndex(args, 0); + [api callFlutterEchoAllNullableTypes:arg_everything + completion:^(AllNullableTypes *_Nullable output, + FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." @@ -1721,6 +1867,30 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + @"callFlutterEchoEnum" + binaryMessenger:binaryMessenger + codec:HostIntegrationCoreApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(callFlutterEchoEnum:completion:)], + @"HostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(callFlutterEchoEnum:completion:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + AnEnum arg_anEnum = [GetNullableObjectAtIndex(args, 0) integerValue]; + [api callFlutterEchoEnum:arg_anEnum + completion:^(AnEnum enumValue, FlutterError *_Nullable error) { + NSNumber *output = [NSNumber numberWithInteger:enumValue]; + callback(wrapResult(output, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." @@ -1889,6 +2059,37 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + @"callFlutterEchoNullableEnum" + binaryMessenger:binaryMessenger + codec:HostIntegrationCoreApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(callFlutterEchoNullableEnum:completion:)], + @"HostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(callFlutterEchoNullableEnum:completion:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSNumber *arg_anEnumAsNumber = GetNullableObjectAtIndex(args, 0); + AnEnumBox *arg_anEnum = + arg_anEnumAsNumber == nil + ? nil + : [[AnEnumBox alloc] initWithValue:[arg_anEnumAsNumber integerValue]]; + [api callFlutterEchoNullableEnum:arg_anEnum + completion:^(AnEnumBox *_Nullable enumValue, + FlutterError *_Nullable error) { + NSNumber *output = + enumValue == nil ? nil + : [NSNumber numberWithInteger:enumValue.value]; + callback(wrapResult(output, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } } @interface FlutterIntegrationCoreApiCodecReader : FlutterStandardReader @end @@ -2013,7 +2214,7 @@ - (void)echoAllTypes:(AllTypes *)arg_everything completion(output, nil); }]; } -- (void)echoAllNullableTypes:(AllNullableTypes *)arg_everything +- (void)echoAllNullableTypes:(nullable AllNullableTypes *)arg_everything completion: (void (^)(AllNullableTypes *_Nullable, FlutterError *_Nullable))completion { FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel @@ -2139,6 +2340,19 @@ - (void)echoMap:(NSDictionary *)arg_aMap completion(output, nil); }]; } +- (void)echoEnum:(AnEnum)arg_anEnum + completion:(void (^)(AnEnum, FlutterError *_Nullable))completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName: + @"dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoEnum" + binaryMessenger:self.binaryMessenger + codec:FlutterIntegrationCoreApiGetCodec()]; + [channel sendMessage:@[ [NSNumber numberWithInteger:arg_anEnum] ] + reply:^(id reply) { + AnEnum output = [reply integerValue]; + completion(output, nil); + }]; +} - (void)echoNullableBool:(nullable NSNumber *)arg_aBool completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion { FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel @@ -2232,6 +2446,24 @@ - (void)echoNullableMap:(nullable NSDictionary *)arg_aMap completion(output, nil); }]; } +- (void)echoNullableEnum:(nullable AnEnumBox *)arg_anEnum + completion:(void (^)(AnEnumBox *_Nullable, FlutterError *_Nullable))completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName: + @"dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoNullableEnum" + binaryMessenger:self.binaryMessenger + codec:FlutterIntegrationCoreApiGetCodec()]; + [channel sendMessage:@[ arg_anEnum == nil ? [NSNull null] + : [NSNumber numberWithInteger:arg_anEnum.value] ] + reply:^(id reply) { + NSNumber *outputAsNumber = reply == [NSNull null] ? nil : reply; + AnEnumBox *output = + outputAsNumber == nil + ? nil + : [[AnEnumBox alloc] initWithValue:[outputAsNumber integerValue]]; + completion(output, nil); + }]; +} - (void)noopAsyncWithCompletion:(void (^)(FlutterError *_Nullable))completion { FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel messageChannelWithName: diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/AlternateLanguageTestPlugin.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/AlternateLanguageTestPlugin.m index 488ff0dfb2c..335913bee5c 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/AlternateLanguageTestPlugin.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/AlternateLanguageTestPlugin.m @@ -92,6 +92,10 @@ - (nullable AllClassesWrapper *)echoClassWrapper:(AllClassesWrapper *)wrapper return wrapper; } +- (AnEnum)echoEnum:(AnEnum)anEnum error:(FlutterError *_Nullable *_Nonnull)error { + return anEnum; +} + - (nullable NSString *)extractNestedNullableStringFrom:(AllClassesWrapper *)wrapper error:(FlutterError *_Nullable *_Nonnull)error { return wrapper.allNullableTypes.aNullableString; @@ -159,6 +163,11 @@ - (nullable id)echoNullableObject:(nullable id)aNullableObject return aNullableMap; } +- (AnEnumBox *_Nullable)echoNullableEnum:(nullable AnEnumBox *)AnEnumBoxed + error:(FlutterError *_Nullable *_Nonnull)error { + return AnEnumBoxed; +} + - (void)noopAsyncWithCompletion:(void (^)(FlutterError *_Nullable))completion { completion(nil); } @@ -229,6 +238,11 @@ - (void)echoAsyncMap:(NSDictionary *)aMap completion(aMap, nil); } +- (void)echoAsyncEnum:(AnEnum)anEnum + completion:(void (^)(AnEnum, FlutterError *_Nullable))completion { + completion(anEnum, nil); +} + - (void)echoAsyncNullableInt:(nullable NSNumber *)anInt completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion { completion(anInt, nil); @@ -272,6 +286,11 @@ - (void)echoAsyncNullableMap:(nullable NSDictionary *)aMap completion(aMap, nil); } +- (void)echoAsyncNullableEnum:(nullable AnEnumBox *)AnEnumBoxed + completion:(void (^)(AnEnumBox *_Nullable, FlutterError *_Nullable))completion { + completion(AnEnumBoxed, nil); +} + - (void)callFlutterNoopWithCompletion:(void (^)(FlutterError *_Nullable))completion { [self.flutterAPI noopWithCompletion:^(FlutterError *error) { completion(error); @@ -370,6 +389,23 @@ - (void)callFlutterEchoMap:(NSDictionary *)aMap }]; } +- (void)callFlutterEchoEnum:(AnEnum)anEnum + completion:(void (^)(AnEnum, FlutterError *_Nullable))completion { + [self.flutterAPI echoEnum:anEnum + completion:^(AnEnum value, FlutterError *error) { + completion(value, error); + }]; +} + +- (void)callFlutterEchoAllNullableTypes:(nullable AllNullableTypes *)everything + completion:(void (^)(AllNullableTypes *_Nullable, + FlutterError *_Nullable))completion { + [self.flutterAPI echoAllNullableTypes:everything + completion:^(AllNullableTypes *value, FlutterError *error) { + completion(value, error); + }]; +} + - (void)callFlutterEchoNullableBool:(nullable NSNumber *)aBool completion: (void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion { @@ -433,4 +469,13 @@ - (void)callFlutterEchoNullableMap:(nullable NSDictionary *)aMap }]; } +- (void)callFlutterEchoNullableEnum:(nullable AnEnumBox *)AnEnumBoxed + completion: + (void (^)(AnEnumBox *_Nullable, FlutterError *_Nullable))completion { + [self.flutterAPI echoNullableEnum:AnEnumBoxed + completion:^(AnEnumBox *value, FlutterError *error) { + completion(value, error); + }]; +} + @end diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.h b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.h index 2cf2d11b4d8..1b558e4f6a8 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.h +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.h @@ -20,6 +20,12 @@ typedef NS_ENUM(NSUInteger, AnEnum) { AnEnumThree = 2, }; +/// Wrapper for AnEnum to allow for nullability. +@interface AnEnumBox : NSObject +@property(nonatomic, assign) AnEnum value; +- (instancetype)initWithValue:(AnEnum)value; +@end + @class AllTypes; @class AllNullableTypes; @class AllClassesWrapper; @@ -73,9 +79,9 @@ typedef NS_ENUM(NSUInteger, AnEnum) { nullableMapWithAnnotations: (nullable NSDictionary *)nullableMapWithAnnotations nullableMapWithObject:(nullable NSDictionary *)nullableMapWithObject - aNullableEnum:(AnEnum)aNullableEnum + aNullableEnum:(nullable AnEnumBox *)aNullableEnum aNullableString:(nullable NSString *)aNullableString - aNullableObject:(id)aNullableObject; + aNullableObject:(nullable id)aNullableObject; @property(nonatomic, strong, nullable) NSNumber *aNullableBool; @property(nonatomic, strong, nullable) NSNumber *aNullableInt; @property(nonatomic, strong, nullable) NSNumber *aNullableInt64; @@ -90,9 +96,9 @@ typedef NS_ENUM(NSUInteger, AnEnum) { @property(nonatomic, strong, nullable) NSDictionary *nullableMapWithAnnotations; @property(nonatomic, strong, nullable) NSDictionary *nullableMapWithObject; -@property(nonatomic, assign) AnEnum aNullableEnum; +@property(nonatomic, strong, nullable) AnEnumBox *aNullableEnum; @property(nonatomic, copy, nullable) NSString *aNullableString; -@property(nonatomic, strong) id aNullableObject; +@property(nonatomic, strong, nullable) id aNullableObject; @end /// A class for testing nested class handling. @@ -177,6 +183,10 @@ NSObject *HostIntegrationCoreApiGetCodec(void); /// @return `nil` only when `error != nil`. - (nullable AllClassesWrapper *)echoClassWrapper:(AllClassesWrapper *)wrapper error:(FlutterError *_Nullable *_Nonnull)error; +/// Returns the passed enum to test serialization and deserialization. +/// +/// @return `nil` only when `error != nil`. +- (AnEnum)echoEnum:(AnEnum)anEnum error:(FlutterError *_Nullable *_Nonnull)error; /// Returns the passed object, to test serialization and deserialization. - (nullable AllNullableTypes *)echoAllNullableTypes:(nullable AllNullableTypes *)everything error:(FlutterError *_Nullable *_Nonnull)error; @@ -225,6 +235,8 @@ NSObject *HostIntegrationCoreApiGetCodec(void); - (nullable NSDictionary *)echoNullableMap: (nullable NSDictionary *)aNullableMap error:(FlutterError *_Nullable *_Nonnull)error; +- (AnEnumBox *_Nullable)echoNullableEnum:(nullable AnEnumBox *)anEnumBoxed + error:(FlutterError *_Nullable *_Nonnull)error; /// A no-op function taking no arguments and returning no value, to sanity /// test basic asynchronous calling. - (void)noopAsyncWithCompletion:(void (^)(FlutterError *_Nullable))completion; @@ -247,13 +259,16 @@ NSObject *HostIntegrationCoreApiGetCodec(void); /// Returns the passed in generic Object asynchronously. - (void)echoAsyncObject:(id)anObject completion:(void (^)(id _Nullable, FlutterError *_Nullable))completion; -/// Returns the passed list, to test serialization and deserialization asynchronously. +/// Returns the passed list, to test asynchronous serialization and deserialization. - (void)echoAsyncList:(NSArray *)aList completion:(void (^)(NSArray *_Nullable, FlutterError *_Nullable))completion; -/// Returns the passed map, to test serialization and deserialization asynchronously. +/// Returns the passed map, to test asynchronous serialization and deserialization. - (void)echoAsyncMap:(NSDictionary *)aMap completion:(void (^)(NSDictionary *_Nullable, FlutterError *_Nullable))completion; +/// Returns the passed enum, to test asynchronous serialization and deserialization. +- (void)echoAsyncEnum:(AnEnum)anEnum + completion:(void (^)(AnEnum, FlutterError *_Nullable))completion; /// Responds with an error from an async function returning a value. - (void)throwAsyncErrorWithCompletion:(void (^)(id _Nullable, FlutterError *_Nullable))completion; /// Responds with an error from an async void function. @@ -287,19 +302,25 @@ NSObject *HostIntegrationCoreApiGetCodec(void); /// Returns the passed in generic Object asynchronously. - (void)echoAsyncNullableObject:(nullable id)anObject completion:(void (^)(id _Nullable, FlutterError *_Nullable))completion; -/// Returns the passed list, to test serialization and deserialization asynchronously. +/// Returns the passed list, to test asynchronous serialization and deserialization. - (void)echoAsyncNullableList:(nullable NSArray *)aList completion:(void (^)(NSArray *_Nullable, FlutterError *_Nullable))completion; -/// Returns the passed map, to test serialization and deserialization asynchronously. +/// Returns the passed map, to test asynchronous serialization and deserialization. - (void)echoAsyncNullableMap:(nullable NSDictionary *)aMap completion:(void (^)(NSDictionary *_Nullable, FlutterError *_Nullable))completion; +/// Returns the passed enum, to test asynchronous serialization and deserialization. +- (void)echoAsyncNullableEnum:(nullable AnEnumBox *)anEnumBoxed + completion:(void (^)(AnEnumBox *_Nullable, FlutterError *_Nullable))completion; - (void)callFlutterNoopWithCompletion:(void (^)(FlutterError *_Nullable))completion; - (void)callFlutterThrowErrorWithCompletion:(void (^)(id _Nullable, FlutterError *_Nullable))completion; - (void)callFlutterThrowErrorFromVoidWithCompletion:(void (^)(FlutterError *_Nullable))completion; - (void)callFlutterEchoAllTypes:(AllTypes *)everything completion:(void (^)(AllTypes *_Nullable, FlutterError *_Nullable))completion; +- (void)callFlutterEchoAllNullableTypes:(nullable AllNullableTypes *)everything + completion:(void (^)(AllNullableTypes *_Nullable, + FlutterError *_Nullable))completion; - (void)callFlutterSendMultipleNullableTypesABool:(nullable NSNumber *)aNullableBool anInt:(nullable NSNumber *)aNullableInt aString:(nullable NSString *)aNullableString @@ -321,6 +342,8 @@ NSObject *HostIntegrationCoreApiGetCodec(void); - (void)callFlutterEchoMap:(NSDictionary *)aMap completion:(void (^)(NSDictionary *_Nullable, FlutterError *_Nullable))completion; +- (void)callFlutterEchoEnum:(AnEnum)anEnum + completion:(void (^)(AnEnum, FlutterError *_Nullable))completion; - (void)callFlutterEchoNullableBool:(nullable NSNumber *)aBool completion: (void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; @@ -342,6 +365,9 @@ NSObject *HostIntegrationCoreApiGetCodec(void); - (void)callFlutterEchoNullableMap:(nullable NSDictionary *)aMap completion:(void (^)(NSDictionary *_Nullable, FlutterError *_Nullable))completion; +- (void)callFlutterEchoNullableEnum:(nullable AnEnumBox *)anEnumBoxed + completion: + (void (^)(AnEnumBox *_Nullable, FlutterError *_Nullable))completion; @end extern void HostIntegrationCoreApiSetup(id binaryMessenger, @@ -365,7 +391,7 @@ NSObject *FlutterIntegrationCoreApiGetCodec(void); - (void)echoAllTypes:(AllTypes *)everything completion:(void (^)(AllTypes *_Nullable, FlutterError *_Nullable))completion; /// Returns the passed object, to test serialization and deserialization. -- (void)echoAllNullableTypes:(AllNullableTypes *)everything +- (void)echoAllNullableTypes:(nullable AllNullableTypes *)everything completion: (void (^)(AllNullableTypes *_Nullable, FlutterError *_Nullable))completion; /// Returns passed in arguments of multiple types. @@ -399,6 +425,8 @@ NSObject *FlutterIntegrationCoreApiGetCodec(void); - (void)echoMap:(NSDictionary *)aMap completion: (void (^)(NSDictionary *_Nullable, FlutterError *_Nullable))completion; +/// Returns the passed enum to test serialization and deserialization. +- (void)echoEnum:(AnEnum)anEnum completion:(void (^)(AnEnum, FlutterError *_Nullable))completion; /// Returns the passed boolean, to test serialization and deserialization. - (void)echoNullableBool:(nullable NSNumber *)aBool completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; @@ -422,6 +450,9 @@ NSObject *FlutterIntegrationCoreApiGetCodec(void); - (void)echoNullableMap:(nullable NSDictionary *)aMap completion:(void (^)(NSDictionary *_Nullable, FlutterError *_Nullable))completion; +/// Returns the passed enum to test serialization and deserialization. +- (void)echoNullableEnum:(nullable AnEnumBox *)anEnumBoxed + completion:(void (^)(AnEnumBox *_Nullable, FlutterError *_Nullable))completion; /// A no-op function taking no arguments and returning no value, to sanity /// test basic asynchronous calling. - (void)noopAsyncWithCompletion:(void (^)(FlutterError *_Nullable))completion; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.m index 524a9dd7037..f68ecd87931 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.m @@ -17,6 +17,16 @@ #error File requires ARC to be enabled. #endif +@implementation AnEnumBox +- (instancetype)initWithValue:(AnEnum)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + static NSArray *wrapResult(id result, FlutterError *error) { if (error) { return @[ @@ -150,9 +160,9 @@ + (instancetype)makeWithANullableBool:(nullable NSNumber *)aNullableBool nullableMapWithAnnotations: (nullable NSDictionary *)nullableMapWithAnnotations nullableMapWithObject:(nullable NSDictionary *)nullableMapWithObject - aNullableEnum:(AnEnum)aNullableEnum + aNullableEnum:(nullable AnEnumBox *)aNullableEnum aNullableString:(nullable NSString *)aNullableString - aNullableObject:(id)aNullableObject { + aNullableObject:(nullable id)aNullableObject { AllNullableTypes *pigeonResult = [[AllNullableTypes alloc] init]; pigeonResult.aNullableBool = aNullableBool; pigeonResult.aNullableInt = aNullableInt; @@ -187,7 +197,12 @@ + (AllNullableTypes *)fromList:(NSArray *)list { pigeonResult.nullableNestedList = GetNullableObjectAtIndex(list, 10); pigeonResult.nullableMapWithAnnotations = GetNullableObjectAtIndex(list, 11); pigeonResult.nullableMapWithObject = GetNullableObjectAtIndex(list, 12); - pigeonResult.aNullableEnum = [GetNullableObjectAtIndex(list, 13) integerValue]; + NSNumber *aNullableEnumAsNumber = GetNullableObjectAtIndex(list, 13); + AnEnumBox *aNullableEnum = + aNullableEnumAsNumber == nil + ? nil + : [[AnEnumBox alloc] initWithValue:[aNullableEnumAsNumber integerValue]]; + pigeonResult.aNullableEnum = aNullableEnum; pigeonResult.aNullableString = GetNullableObjectAtIndex(list, 14); pigeonResult.aNullableObject = GetNullableObjectAtIndex(list, 15); return pigeonResult; @@ -210,7 +225,8 @@ - (NSArray *)toList { (self.nullableNestedList ?: [NSNull null]), (self.nullableMapWithAnnotations ?: [NSNull null]), (self.nullableMapWithObject ?: [NSNull null]), - @(self.aNullableEnum), + (self.aNullableEnum == nil ? [NSNull null] + : [NSNumber numberWithInteger:self.aNullableEnum.value]), (self.aNullableString ?: [NSNull null]), (self.aNullableObject ?: [NSNull null]), ]; @@ -636,6 +652,29 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + /// Returns the passed enum to test serialization and deserialization. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName: + @"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoEnum" + binaryMessenger:binaryMessenger + codec:HostIntegrationCoreApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(echoEnum:error:)], + @"HostIntegrationCoreApi api (%@) doesn't respond to @selector(echoEnum:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + AnEnum arg_anEnum = [GetNullableObjectAtIndex(args, 0) integerValue]; + FlutterError *error; + AnEnum enumValue = [api echoEnum:arg_anEnum error:&error]; + NSNumber *output = [NSNumber numberWithInteger:enumValue]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } /// Returns the passed object, to test serialization and deserialization. { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] @@ -922,6 +961,33 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + @"echoNullableEnum" + binaryMessenger:binaryMessenger + codec:HostIntegrationCoreApiGetCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(echoNullableEnum:error:)], + @"HostIntegrationCoreApi api (%@) doesn't respond to @selector(echoNullableEnum:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSNumber *arg_anEnumAsNumber = GetNullableObjectAtIndex(args, 0); + AnEnumBox *arg_anEnum = + arg_anEnumAsNumber == nil + ? nil + : [[AnEnumBox alloc] initWithValue:[arg_anEnumAsNumber integerValue]]; + FlutterError *error; + AnEnumBox *enumBox = [api echoNullableEnum:arg_anEnum error:&error]; + NSNumber *output = enumBox == nil ? nil : [NSNumber numberWithInteger:enumBox.value]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } /// A no-op function taking no arguments and returning no value, to sanity /// test basic asynchronous calling. { @@ -1089,7 +1155,7 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName: @@ -1113,7 +1179,7 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName: @@ -1138,6 +1204,31 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + /// Returns the passed enum, to test asynchronous serialization and deserialization. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName: + @"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncEnum" + binaryMessenger:binaryMessenger + codec:HostIntegrationCoreApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(echoAsyncEnum:completion:)], + @"HostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(echoAsyncEnum:completion:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + AnEnum arg_anEnum = [GetNullableObjectAtIndex(args, 0) integerValue]; + [api echoAsyncEnum:arg_anEnum + completion:^(AnEnum enumValue, FlutterError *_Nullable error) { + NSNumber *output = [NSNumber numberWithInteger:enumValue]; + callback(wrapResult(output, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } /// Responds with an error from an async function returning a value. { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] @@ -1396,7 +1487,7 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." @@ -1420,7 +1511,7 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." @@ -1445,6 +1536,37 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + /// Returns the passed enum, to test asynchronous serialization and deserialization. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + @"echoAsyncNullableEnum" + binaryMessenger:binaryMessenger + codec:HostIntegrationCoreApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(echoAsyncNullableEnum:completion:)], + @"HostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(echoAsyncNullableEnum:completion:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSNumber *arg_anEnumAsNumber = GetNullableObjectAtIndex(args, 0); + AnEnumBox *arg_anEnum = + arg_anEnumAsNumber == nil + ? nil + : [[AnEnumBox alloc] initWithValue:[arg_anEnumAsNumber integerValue]]; + [api + echoAsyncNullableEnum:arg_anEnum + completion:^(AnEnumBox *_Nullable enumValue, FlutterError *_Nullable error) { + NSNumber *output = + enumValue == nil ? nil : [NSNumber numberWithInteger:enumValue.value]; + callback(wrapResult(output, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName: @@ -1529,6 +1651,30 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + @"callFlutterEchoAllNullableTypes" + binaryMessenger:binaryMessenger + codec:HostIntegrationCoreApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(callFlutterEchoAllNullableTypes:completion:)], + @"HostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(callFlutterEchoAllNullableTypes:completion:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + AllNullableTypes *arg_everything = GetNullableObjectAtIndex(args, 0); + [api callFlutterEchoAllNullableTypes:arg_everything + completion:^(AllNullableTypes *_Nullable output, + FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." @@ -1721,6 +1867,30 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + @"callFlutterEchoEnum" + binaryMessenger:binaryMessenger + codec:HostIntegrationCoreApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(callFlutterEchoEnum:completion:)], + @"HostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(callFlutterEchoEnum:completion:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + AnEnum arg_anEnum = [GetNullableObjectAtIndex(args, 0) integerValue]; + [api callFlutterEchoEnum:arg_anEnum + completion:^(AnEnum enumValue, FlutterError *_Nullable error) { + NSNumber *output = [NSNumber numberWithInteger:enumValue]; + callback(wrapResult(output, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." @@ -1889,6 +2059,37 @@ void HostIntegrationCoreApiSetup(id binaryMessenger, [channel setMessageHandler:nil]; } } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:@"dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + @"callFlutterEchoNullableEnum" + binaryMessenger:binaryMessenger + codec:HostIntegrationCoreApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(callFlutterEchoNullableEnum:completion:)], + @"HostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(callFlutterEchoNullableEnum:completion:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSNumber *arg_anEnumAsNumber = GetNullableObjectAtIndex(args, 0); + AnEnumBox *arg_anEnum = + arg_anEnumAsNumber == nil + ? nil + : [[AnEnumBox alloc] initWithValue:[arg_anEnumAsNumber integerValue]]; + [api callFlutterEchoNullableEnum:arg_anEnum + completion:^(AnEnumBox *_Nullable enumValue, + FlutterError *_Nullable error) { + NSNumber *output = + enumValue == nil ? nil + : [NSNumber numberWithInteger:enumValue.value]; + callback(wrapResult(output, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } } @interface FlutterIntegrationCoreApiCodecReader : FlutterStandardReader @end @@ -2013,7 +2214,7 @@ - (void)echoAllTypes:(AllTypes *)arg_everything completion(output, nil); }]; } -- (void)echoAllNullableTypes:(AllNullableTypes *)arg_everything +- (void)echoAllNullableTypes:(nullable AllNullableTypes *)arg_everything completion: (void (^)(AllNullableTypes *_Nullable, FlutterError *_Nullable))completion { FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel @@ -2139,6 +2340,19 @@ - (void)echoMap:(NSDictionary *)arg_aMap completion(output, nil); }]; } +- (void)echoEnum:(AnEnum)arg_anEnum + completion:(void (^)(AnEnum, FlutterError *_Nullable))completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName: + @"dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoEnum" + binaryMessenger:self.binaryMessenger + codec:FlutterIntegrationCoreApiGetCodec()]; + [channel sendMessage:@[ [NSNumber numberWithInteger:arg_anEnum] ] + reply:^(id reply) { + AnEnum output = [reply integerValue]; + completion(output, nil); + }]; +} - (void)echoNullableBool:(nullable NSNumber *)arg_aBool completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion { FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel @@ -2232,6 +2446,24 @@ - (void)echoNullableMap:(nullable NSDictionary *)arg_aMap completion(output, nil); }]; } +- (void)echoNullableEnum:(nullable AnEnumBox *)arg_anEnum + completion:(void (^)(AnEnumBox *_Nullable, FlutterError *_Nullable))completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName: + @"dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoNullableEnum" + binaryMessenger:self.binaryMessenger + codec:FlutterIntegrationCoreApiGetCodec()]; + [channel sendMessage:@[ arg_anEnum == nil ? [NSNull null] + : [NSNumber numberWithInteger:arg_anEnum.value] ] + reply:^(id reply) { + NSNumber *outputAsNumber = reply == [NSNull null] ? nil : reply; + AnEnumBox *output = + outputAsNumber == nil + ? nil + : [[AnEnumBox alloc] initWithValue:[outputAsNumber integerValue]]; + completion(output, nil); + }]; +} - (void)noopAsyncWithCompletion:(void (^)(FlutterError *_Nullable))completion { FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel messageChannelWithName: diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart index c43e2ef37bb..954ed8e1da1 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart @@ -104,12 +104,8 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { true); expect(allNullableTypesOne.aNullableObject, allNullableTypesTwo.aNullableObject); - // TODO(stuartmorgan): Fix and re-enable. - // See https://github.com/flutter/flutter/issues/118733 - if (targetGenerator != TargetGenerator.objc) { - expect( - allNullableTypesOne.aNullableEnum, allNullableTypesTwo.aNullableEnum); - } + expect( + allNullableTypesOne.aNullableEnum, allNullableTypesTwo.aNullableEnum); } void compareAllClassesWrapper( @@ -439,6 +435,15 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { expect(mapEquals(echoObject, sentObject), true); }); + testWidgets('enums serialize and deserialize correctly', + (WidgetTester _) async { + final HostIntegrationCoreApi api = HostIntegrationCoreApi(); + + const AnEnum sentEnum = AnEnum.two; + final AnEnum receivedEnum = await api.echoEnum(sentEnum); + expect(receivedEnum, sentEnum); + }); + testWidgets('Nullable Int serialize and deserialize correctly', (WidgetTester _) async { final HostIntegrationCoreApi api = HostIntegrationCoreApi(); @@ -592,6 +597,15 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { expect(mapEquals(echoObject, sentObject), true); }); + testWidgets('nullable enums serialize and deserialize correctly', + (WidgetTester _) async { + final HostIntegrationCoreApi api = HostIntegrationCoreApi(); + + const AnEnum sentEnum = AnEnum.three; + final AnEnum? echoEnum = await api.echoNullableEnum(sentEnum); + expect(echoEnum, sentEnum); + }); + testWidgets('null lists serialize and deserialize correctly', (WidgetTester _) async { final HostIntegrationCoreApi api = HostIntegrationCoreApi(); @@ -607,6 +621,15 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { final Map? echoObject = await api.echoNullableMap(null); expect(mapEquals(echoObject, null), true); }); + + testWidgets('null enums serialize and deserialize correctly', + (WidgetTester _) async { + final HostIntegrationCoreApi api = HostIntegrationCoreApi(); + + const AnEnum? sentEnum = null; + final AnEnum? echoEnum = await api.echoNullableEnum(sentEnum); + expect(echoEnum, sentEnum); + }); }); group('Host async API tests', () { @@ -783,6 +806,15 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { expect(mapEquals(echoObject, sentObject), true); }); + testWidgets('enums serialize and deserialize correctly', + (WidgetTester _) async { + final HostIntegrationCoreApi api = HostIntegrationCoreApi(); + + const AnEnum sentEnum = AnEnum.three; + final AnEnum echoEnum = await api.echoAsyncEnum(sentEnum); + expect(echoEnum, sentEnum); + }); + testWidgets('nullable Int async serialize and deserialize correctly', (WidgetTester _) async { final HostIntegrationCoreApi api = HostIntegrationCoreApi(); @@ -891,6 +923,15 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { expect(mapEquals(echoObject, sentObject), true); }); + testWidgets('nullable enums serialize and deserialize correctly', + (WidgetTester _) async { + final HostIntegrationCoreApi api = HostIntegrationCoreApi(); + + const AnEnum sentEnum = AnEnum.three; + final AnEnum? echoEnum = await api.echoAsyncNullableEnum(sentEnum); + expect(echoEnum, sentEnum); + }); + testWidgets('null Ints async serialize and deserialize correctly', (WidgetTester _) async { final HostIntegrationCoreApi api = HostIntegrationCoreApi(); @@ -956,6 +997,15 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { await api.echoAsyncNullableMap(null); expect(mapEquals(echoObject, null), true); }); + + testWidgets('null enums serialize and deserialize correctly', + (WidgetTester _) async { + final HostIntegrationCoreApi api = HostIntegrationCoreApi(); + + const AnEnum? sentEnum = null; + final AnEnum? echoEnum = await api.echoAsyncNullableEnum(null); + expect(echoEnum, sentEnum); + }); }); // These tests rely on the async Dart->host calls to work correctly, since @@ -1118,6 +1168,15 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { expect(mapEquals(echoObject, sentObject), true); }); + testWidgets('enums serialize and deserialize correctly', + (WidgetTester _) async { + final HostIntegrationCoreApi api = HostIntegrationCoreApi(); + + const AnEnum sentEnum = AnEnum.three; + final AnEnum echoEnum = await api.callFlutterEchoEnum(sentEnum); + expect(echoEnum, sentEnum); + }); + testWidgets('nullable booleans serialize and deserialize correctly', (WidgetTester _) async { final HostIntegrationCoreApi api = HostIntegrationCoreApi(); @@ -1272,6 +1331,24 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { await api.callFlutterEchoNullableMap(null); expect(mapEquals(echoObject, null), true); }); + + testWidgets('nullable enums serialize and deserialize correctly', + (WidgetTester _) async { + final HostIntegrationCoreApi api = HostIntegrationCoreApi(); + + const AnEnum sentEnum = AnEnum.three; + final AnEnum? echoEnum = await api.callFlutterEchoNullableEnum(sentEnum); + expect(echoEnum, sentEnum); + }); + + testWidgets('null enums serialize and deserialize correctly', + (WidgetTester _) async { + final HostIntegrationCoreApi api = HostIntegrationCoreApi(); + + const AnEnum? sentEnum = null; + final AnEnum? echoEnum = await api.callFlutterEchoNullableEnum(sentEnum); + expect(echoEnum, sentEnum); + }); }); } @@ -1282,7 +1359,7 @@ class _FlutterApiTestImplementation implements FlutterIntegrationCoreApi { } @override - AllNullableTypes echoAllNullableTypes(AllNullableTypes everything) { + AllNullableTypes? echoAllNullableTypes(AllNullableTypes? everything) { return everything; } @@ -1329,6 +1406,9 @@ class _FlutterApiTestImplementation implements FlutterIntegrationCoreApi { @override Map echoMap(Map aMap) => aMap; + @override + AnEnum echoEnum(AnEnum anEnum) => anEnum; + @override bool? echoNullableBool(bool? aBool) => aBool; @@ -1350,6 +1430,9 @@ class _FlutterApiTestImplementation implements FlutterIntegrationCoreApi { @override Uint8List? echoNullableUint8List(Uint8List? aList) => aList; + @override + AnEnum? echoNullableEnum(AnEnum? anEnum) => anEnum; + @override Future noopAsync() async {} diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart index 6d93313f6f1..08b223cb192 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart @@ -689,6 +689,35 @@ class HostIntegrationCoreApi { } } + /// Returns the passed enum to test serialization and deserialization. + Future echoEnum(AnEnum arg_anEnum) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoEnum', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_anEnum.index]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return AnEnum.values[replyList[0]! as int]; + } + } + /// Returns the passed object, to test serialization and deserialization. Future echoAllNullableTypes( AllNullableTypes? arg_everything) async { @@ -997,6 +1026,31 @@ class HostIntegrationCoreApi { } } + Future echoNullableEnum(AnEnum? arg_anEnum) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoNullableEnum', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_anEnum?.index]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return (replyList[0] as int?) == null + ? null + : AnEnum.values[replyList[0]! as int]; + } + } + /// A no-op function taking no arguments and returning no value, to sanity /// test basic asynchronous calling. Future noopAsync() async { @@ -1195,7 +1249,7 @@ class HostIntegrationCoreApi { } } - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. Future> echoAsyncList(List arg_aList) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncList', @@ -1224,7 +1278,7 @@ class HostIntegrationCoreApi { } } - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. Future> echoAsyncMap( Map arg_aMap) async { final BasicMessageChannel channel = BasicMessageChannel( @@ -1254,6 +1308,35 @@ class HostIntegrationCoreApi { } } + /// Returns the passed enum, to test asynchronous serialization and deserialization. + Future echoAsyncEnum(AnEnum arg_anEnum) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncEnum', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_anEnum.index]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return AnEnum.values[replyList[0]! as int]; + } + } + /// Responds with an error from an async function returning a value. Future throwAsyncError() async { final BasicMessageChannel channel = BasicMessageChannel( @@ -1522,7 +1605,7 @@ class HostIntegrationCoreApi { } } - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. Future?> echoAsyncNullableList(List? arg_aList) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncNullableList', @@ -1546,7 +1629,7 @@ class HostIntegrationCoreApi { } } - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. Future?> echoAsyncNullableMap( Map? arg_aMap) async { final BasicMessageChannel channel = BasicMessageChannel( @@ -1571,6 +1654,32 @@ class HostIntegrationCoreApi { } } + /// Returns the passed enum, to test asynchronous serialization and deserialization. + Future echoAsyncNullableEnum(AnEnum? arg_anEnum) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncNullableEnum', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_anEnum?.index]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return (replyList[0] as int?) == null + ? null + : AnEnum.values[replyList[0]! as int]; + } + } + Future callFlutterNoop() async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterNoop', @@ -1665,6 +1774,30 @@ class HostIntegrationCoreApi { } } + Future callFlutterEchoAllNullableTypes( + AllNullableTypes? arg_everything) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoAllNullableTypes', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_everything]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return (replyList[0] as AllNullableTypes?); + } + } + Future callFlutterSendMultipleNullableTypes( bool? arg_aNullableBool, int? arg_aNullableInt, @@ -1894,6 +2027,34 @@ class HostIntegrationCoreApi { } } + Future callFlutterEchoEnum(AnEnum arg_anEnum) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoEnum', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_anEnum.index]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return AnEnum.values[replyList[0]! as int]; + } + } + Future callFlutterEchoNullableBool(bool? arg_aBool) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoNullableBool', @@ -2057,6 +2218,31 @@ class HostIntegrationCoreApi { return (replyList[0] as Map?)?.cast(); } } + + Future callFlutterEchoNullableEnum(AnEnum? arg_anEnum) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoNullableEnum', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_anEnum?.index]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return (replyList[0] as int?) == null + ? null + : AnEnum.values[replyList[0]! as int]; + } + } } class _FlutterIntegrationCoreApiCodec extends StandardMessageCodec { @@ -2116,7 +2302,7 @@ abstract class FlutterIntegrationCoreApi { AllTypes echoAllTypes(AllTypes everything); /// Returns the passed object, to test serialization and deserialization. - AllNullableTypes echoAllNullableTypes(AllNullableTypes everything); + AllNullableTypes? echoAllNullableTypes(AllNullableTypes? everything); /// Returns passed in arguments of multiple types. /// @@ -2145,6 +2331,9 @@ abstract class FlutterIntegrationCoreApi { /// Returns the passed map, to test serialization and deserialization. Map echoMap(Map aMap); + /// Returns the passed enum to test serialization and deserialization. + AnEnum echoEnum(AnEnum anEnum); + /// Returns the passed boolean, to test serialization and deserialization. bool? echoNullableBool(bool? aBool); @@ -2166,6 +2355,9 @@ abstract class FlutterIntegrationCoreApi { /// Returns the passed map, to test serialization and deserialization. Map? echoNullableMap(Map? aMap); + /// Returns the passed enum to test serialization and deserialization. + AnEnum? echoNullableEnum(AnEnum? anEnum); + /// A no-op function taking no arguments and returning no value, to sanity /// test basic asynchronous calling. Future noopAsync(); @@ -2254,10 +2446,8 @@ abstract class FlutterIntegrationCoreApi { final List args = (message as List?)!; final AllNullableTypes? arg_everything = (args[0] as AllNullableTypes?); - assert(arg_everything != null, - 'Argument for dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoAllNullableTypes was null, expected non-null AllNullableTypes.'); - final AllNullableTypes output = - api.echoAllNullableTypes(arg_everything!); + final AllNullableTypes? output = + api.echoAllNullableTypes(arg_everything); return output; }); } @@ -2425,6 +2615,27 @@ abstract class FlutterIntegrationCoreApi { }); } } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoEnum', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoEnum was null.'); + final List args = (message as List?)!; + final AnEnum? arg_anEnum = + args[0] == null ? null : AnEnum.values[args[0]! as int]; + assert(arg_anEnum != null, + 'Argument for dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoEnum was null, expected non-null AnEnum.'); + final AnEnum output = api.echoEnum(arg_anEnum!); + return output.index; + }); + } + } { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoNullableBool', @@ -2553,6 +2764,25 @@ abstract class FlutterIntegrationCoreApi { }); } } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoNullableEnum', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoNullableEnum was null.'); + final List args = (message as List?)!; + final AnEnum? arg_anEnum = + args[0] == null ? null : AnEnum.values[args[0]! as int]; + final AnEnum? output = api.echoNullableEnum(arg_anEnum); + return output?.index; + }); + } + } { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.noopAsync', diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt index cb8aaddb4f8..ab6e8622cd4 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt @@ -331,6 +331,8 @@ interface HostIntegrationCoreApi { fun echoMap(aMap: Map): Map /** Returns the passed map to test nested class serialization and deserialization. */ fun echoClassWrapper(wrapper: AllClassesWrapper): AllClassesWrapper + /** Returns the passed enum to test serialization and deserialization. */ + fun echoEnum(anEnum: AnEnum): AnEnum /** Returns the passed object, to test serialization and deserialization. */ fun echoAllNullableTypes(everything: AllNullableTypes?): AllNullableTypes? /** @@ -361,6 +363,7 @@ interface HostIntegrationCoreApi { fun echoNullableList(aNullableList: List?): List? /** Returns the passed map, to test serialization and deserialization. */ fun echoNullableMap(aNullableMap: Map?): Map? + fun echoNullableEnum(anEnum: AnEnum?): AnEnum? /** * A no-op function taking no arguments and returning no value, to sanity * test basic asynchronous calling. @@ -378,10 +381,12 @@ interface HostIntegrationCoreApi { fun echoAsyncUint8List(aUint8List: ByteArray, callback: (Result) -> Unit) /** Returns the passed in generic Object asynchronously. */ fun echoAsyncObject(anObject: Any, callback: (Result) -> Unit) - /** Returns the passed list, to test serialization and deserialization asynchronously. */ + /** Returns the passed list, to test asynchronous serialization and deserialization. */ fun echoAsyncList(aList: List, callback: (Result>) -> Unit) - /** Returns the passed map, to test serialization and deserialization asynchronously. */ + /** Returns the passed map, to test asynchronous serialization and deserialization. */ fun echoAsyncMap(aMap: Map, callback: (Result>) -> Unit) + /** Returns the passed enum, to test asynchronous serialization and deserialization. */ + fun echoAsyncEnum(anEnum: AnEnum, callback: (Result) -> Unit) /** Responds with an error from an async function returning a value. */ fun throwAsyncError(callback: (Result) -> Unit) /** Responds with an error from an async void function. */ @@ -404,14 +409,17 @@ interface HostIntegrationCoreApi { fun echoAsyncNullableUint8List(aUint8List: ByteArray?, callback: (Result) -> Unit) /** Returns the passed in generic Object asynchronously. */ fun echoAsyncNullableObject(anObject: Any?, callback: (Result) -> Unit) - /** Returns the passed list, to test serialization and deserialization asynchronously. */ + /** Returns the passed list, to test asynchronous serialization and deserialization. */ fun echoAsyncNullableList(aList: List?, callback: (Result?>) -> Unit) - /** Returns the passed map, to test serialization and deserialization asynchronously. */ + /** Returns the passed map, to test asynchronous serialization and deserialization. */ fun echoAsyncNullableMap(aMap: Map?, callback: (Result?>) -> Unit) + /** Returns the passed enum, to test asynchronous serialization and deserialization. */ + fun echoAsyncNullableEnum(anEnum: AnEnum?, callback: (Result) -> Unit) fun callFlutterNoop(callback: (Result) -> Unit) fun callFlutterThrowError(callback: (Result) -> Unit) fun callFlutterThrowErrorFromVoid(callback: (Result) -> Unit) fun callFlutterEchoAllTypes(everything: AllTypes, callback: (Result) -> Unit) + fun callFlutterEchoAllNullableTypes(everything: AllNullableTypes?, callback: (Result) -> Unit) fun callFlutterSendMultipleNullableTypes(aNullableBool: Boolean?, aNullableInt: Long?, aNullableString: String?, callback: (Result) -> Unit) fun callFlutterEchoBool(aBool: Boolean, callback: (Result) -> Unit) fun callFlutterEchoInt(anInt: Long, callback: (Result) -> Unit) @@ -420,6 +428,7 @@ interface HostIntegrationCoreApi { fun callFlutterEchoUint8List(aList: ByteArray, callback: (Result) -> Unit) fun callFlutterEchoList(aList: List, callback: (Result>) -> Unit) fun callFlutterEchoMap(aMap: Map, callback: (Result>) -> Unit) + fun callFlutterEchoEnum(anEnum: AnEnum, callback: (Result) -> Unit) fun callFlutterEchoNullableBool(aBool: Boolean?, callback: (Result) -> Unit) fun callFlutterEchoNullableInt(anInt: Long?, callback: (Result) -> Unit) fun callFlutterEchoNullableDouble(aDouble: Double?, callback: (Result) -> Unit) @@ -427,6 +436,7 @@ interface HostIntegrationCoreApi { fun callFlutterEchoNullableUint8List(aList: ByteArray?, callback: (Result) -> Unit) fun callFlutterEchoNullableList(aList: List?, callback: (Result?>) -> Unit) fun callFlutterEchoNullableMap(aMap: Map?, callback: (Result?>) -> Unit) + fun callFlutterEchoNullableEnum(anEnum: AnEnum?, callback: (Result) -> Unit) companion object { /** The codec used by HostIntegrationCoreApi. */ @@ -682,6 +692,24 @@ interface HostIntegrationCoreApi { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoEnum", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val anEnumArg = AnEnum.ofRaw(args[0] as Int)!! + var wrapped: List + try { + wrapped = listOf(api.echoEnum(anEnumArg).raw) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAllNullableTypes", codec) if (api != null) { @@ -900,6 +928,24 @@ interface HostIntegrationCoreApi { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoNullableEnum", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val anEnumArg = if (args[0] == null) null else AnEnum.ofRaw(args[0] as Int) + var wrapped: List + try { + wrapped = listOf(api.echoNullableEnum(anEnumArg)?.raw) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.noopAsync", codec) if (api != null) { @@ -1077,6 +1123,26 @@ interface HostIntegrationCoreApi { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncEnum", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val anEnumArg = AnEnum.ofRaw(args[0] as Int)!! + api.echoAsyncEnum(anEnumArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data!!.raw)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.throwAsyncError", codec) if (api != null) { @@ -1330,6 +1396,26 @@ interface HostIntegrationCoreApi { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncNullableEnum", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val anEnumArg = if (args[0] == null) null else AnEnum.ofRaw(args[0] as Int) + api.echoAsyncNullableEnum(anEnumArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data?.raw)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterNoop", codec) if (api != null) { @@ -1402,6 +1488,26 @@ interface HostIntegrationCoreApi { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoAllNullableTypes", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val everythingArg = args[0] as AllNullableTypes? + api.callFlutterEchoAllNullableTypes(everythingArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterSendMultipleNullableTypes", codec) if (api != null) { @@ -1564,6 +1670,26 @@ interface HostIntegrationCoreApi { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoEnum", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val anEnumArg = AnEnum.ofRaw(args[0] as Int)!! + api.callFlutterEchoEnum(anEnumArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data!!.raw)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoNullableBool", codec) if (api != null) { @@ -1704,6 +1830,26 @@ interface HostIntegrationCoreApi { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoNullableEnum", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val anEnumArg = if (args[0] == null) null else AnEnum.ofRaw(args[0] as Int) + api.callFlutterEchoNullableEnum(anEnumArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data?.raw)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } } } } @@ -1805,10 +1951,10 @@ class FlutterIntegrationCoreApi(private val binaryMessenger: BinaryMessenger) { } } /** Returns the passed object, to test serialization and deserialization. */ - fun echoAllNullableTypes(everythingArg: AllNullableTypes, callback: (AllNullableTypes) -> Unit) { + fun echoAllNullableTypes(everythingArg: AllNullableTypes?, callback: (AllNullableTypes?) -> Unit) { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoAllNullableTypes", codec) channel.send(listOf(everythingArg)) { - val result = it as AllNullableTypes + val result = it as AllNullableTypes? callback(result) } } @@ -1880,6 +2026,14 @@ class FlutterIntegrationCoreApi(private val binaryMessenger: BinaryMessenger) { callback(result) } } + /** Returns the passed enum to test serialization and deserialization. */ + fun echoEnum(anEnumArg: AnEnum, callback: (AnEnum) -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoEnum", codec) + channel.send(listOf(anEnumArg.raw)) { + val result = AnEnum.ofRaw(it as Int)!! + callback(result) + } + } /** Returns the passed boolean, to test serialization and deserialization. */ fun echoNullableBool(aBoolArg: Boolean?, callback: (Boolean?) -> Unit) { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoNullableBool", codec) @@ -1936,6 +2090,16 @@ class FlutterIntegrationCoreApi(private val binaryMessenger: BinaryMessenger) { callback(result) } } + /** Returns the passed enum to test serialization and deserialization. */ + fun echoNullableEnum(anEnumArg: AnEnum?, callback: (AnEnum?) -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoNullableEnum", codec) + channel.send(listOf(anEnumArg?.raw)) { + val result = (it as Int?)?.let { + AnEnum.ofRaw(it) + } + callback(result) + } + } /** * A no-op function taking no arguments and returning no value, to sanity * test basic asynchronous calling. diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt index 93a6615752f..842c8ae72e0 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt @@ -87,6 +87,10 @@ class TestPlugin: FlutterPlugin, HostIntegrationCoreApi { return wrapper } + override fun echoEnum(anEnum: AnEnum): AnEnum { + return anEnum + } + override fun extractNestedNullableString(wrapper: AllClassesWrapper): String? { return wrapper.allNullableTypes.aNullableString } @@ -130,6 +134,11 @@ class TestPlugin: FlutterPlugin, HostIntegrationCoreApi { override fun echoNullableMap(aNullableMap: Map?): Map? { return aNullableMap } + + override fun echoNullableEnum(anEnum: AnEnum?): AnEnum? { + return anEnum + } + override fun noopAsync(callback: (Result) -> Unit) { callback(Result.success(Unit)) } @@ -186,6 +195,10 @@ class TestPlugin: FlutterPlugin, HostIntegrationCoreApi { callback(Result.success(aMap)) } + override fun echoAsyncEnum(anEnum: AnEnum, callback: (Result) -> Unit) { + callback(Result.success(anEnum)) + } + override fun echoAsyncNullableInt(anInt: Long?, callback: (Result) -> Unit) { callback(Result.success(anInt)) } @@ -218,6 +231,10 @@ class TestPlugin: FlutterPlugin, HostIntegrationCoreApi { callback(Result.success(aMap)) } + override fun echoAsyncNullableEnum(anEnum: AnEnum?, callback: (Result) -> Unit) { + callback(Result.success(anEnum)) + } + override fun callFlutterNoop(callback: (Result) -> Unit) { flutterApi!!.noop() { callback(Result.success(Unit)) } } @@ -274,6 +291,14 @@ class TestPlugin: FlutterPlugin, HostIntegrationCoreApi { flutterApi!!.echoMap(aMap) { echo -> callback(Result.success(echo)) } } + override fun callFlutterEchoEnum(anEnum: AnEnum, callback: (Result) -> Unit) { + flutterApi!!.echoEnum(anEnum) { echo -> callback(Result.success(echo)) } + } + + override fun callFlutterEchoAllNullableTypes(everything: AllNullableTypes?, callback: (Result) -> Unit) { + flutterApi!!.echoAllNullableTypes(everything) { echo -> callback(Result.success(echo)) } + } + override fun callFlutterEchoNullableBool(aBool: Boolean?, callback: (Result) -> Unit) { flutterApi!!.echoNullableBool(aBool) { echo -> callback(Result.success(echo)) } } @@ -302,4 +327,8 @@ class TestPlugin: FlutterPlugin, HostIntegrationCoreApi { flutterApi!!.echoNullableMap(aMap) { echo -> callback(Result.success(echo)) } } + override fun callFlutterEchoNullableEnum(anEnum: AnEnum?, callback: (Result) -> Unit) { + flutterApi!!.echoNullableEnum(anEnum) { echo -> callback(Result.success(echo)) } + } + } diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AllDatatypesTest.kt b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AllDatatypesTest.kt index abfae652726..af1ff21bb2e 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AllDatatypesTest.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AllDatatypesTest.kt @@ -73,7 +73,8 @@ internal class AllDatatypesTest: TestCase() { var didCall = false api.echoAllNullableTypes(everything) { didCall = true - assertNull(it.aNullableBool) + assertNotNull(it) + assertNull(it!!.aNullableBool) assertNull(it.aNullableInt) assertNull(it.aNullableDouble) assertNull(it.aNullableString) diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AllDatatypesTests.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AllDatatypesTests.swift index 4992841786e..2373673adc3 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AllDatatypesTests.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AllDatatypesTests.swift @@ -16,19 +16,20 @@ class AllDatatypesTests: XCTestCase { let expectation = XCTestExpectation(description: "callback") api.echoNullable(everything) { result in - XCTAssertNil(result.aNullableBool) - XCTAssertNil(result.aNullableInt) - XCTAssertNil(result.aNullableDouble) - XCTAssertNil(result.aNullableString) - XCTAssertNil(result.aNullableByteArray) - XCTAssertNil(result.aNullable4ByteArray) - XCTAssertNil(result.aNullable8ByteArray) - XCTAssertNil(result.aNullableFloatArray) - XCTAssertNil(result.aNullableList) - XCTAssertNil(result.aNullableMap) - XCTAssertNil(result.nullableNestedList) - XCTAssertNil(result.nullableMapWithAnnotations) - XCTAssertNil(result.nullableMapWithObject) + XCTAssertNotNil(result) + XCTAssertNil(result!.aNullableBool) + XCTAssertNil(result!.aNullableInt) + XCTAssertNil(result!.aNullableDouble) + XCTAssertNil(result!.aNullableString) + XCTAssertNil(result!.aNullableByteArray) + XCTAssertNil(result!.aNullable4ByteArray) + XCTAssertNil(result!.aNullable8ByteArray) + XCTAssertNil(result!.aNullableFloatArray) + XCTAssertNil(result!.aNullableList) + XCTAssertNil(result!.aNullableMap) + XCTAssertNil(result!.nullableNestedList) + XCTAssertNil(result!.nullableMapWithAnnotations) + XCTAssertNil(result!.nullableMapWithObject) expectation.fulfill() } @@ -58,19 +59,20 @@ class AllDatatypesTests: XCTestCase { let expectation = XCTestExpectation(description: "callback") api.echoNullable(everything) { result in - XCTAssertEqual(result.aNullableBool, everything.aNullableBool) - XCTAssertEqual(result.aNullableInt, everything.aNullableInt) - XCTAssertEqual(result.aNullableDouble, everything.aNullableDouble) - XCTAssertEqual(result.aNullableString, everything.aNullableString) - XCTAssertEqual(result.aNullableByteArray, everything.aNullableByteArray) - XCTAssertEqual(result.aNullable4ByteArray, everything.aNullable4ByteArray) - XCTAssertEqual(result.aNullable8ByteArray, everything.aNullable8ByteArray) - XCTAssertEqual(result.aNullableFloatArray, everything.aNullableFloatArray) - XCTAssert(equalsList(result.aNullableList, everything.aNullableList)) - XCTAssert(equalsDictionary(result.aNullableMap, everything.aNullableMap)) - XCTAssertEqual(result.nullableNestedList, everything.nullableNestedList) - XCTAssertEqual(result.nullableMapWithAnnotations, everything.nullableMapWithAnnotations) - XCTAssert(equalsDictionary(result.nullableMapWithObject, everything.nullableMapWithObject)) + XCTAssertNotNil(result) + XCTAssertEqual(result!.aNullableBool, everything.aNullableBool) + XCTAssertEqual(result!.aNullableInt, everything.aNullableInt) + XCTAssertEqual(result!.aNullableDouble, everything.aNullableDouble) + XCTAssertEqual(result!.aNullableString, everything.aNullableString) + XCTAssertEqual(result!.aNullableByteArray, everything.aNullableByteArray) + XCTAssertEqual(result!.aNullable4ByteArray, everything.aNullable4ByteArray) + XCTAssertEqual(result!.aNullable8ByteArray, everything.aNullable8ByteArray) + XCTAssertEqual(result!.aNullableFloatArray, everything.aNullableFloatArray) + XCTAssert(equalsList(result!.aNullableList, everything.aNullableList)) + XCTAssert(equalsDictionary(result!.aNullableMap, everything.aNullableMap)) + XCTAssertEqual(result!.nullableNestedList, everything.nullableNestedList) + XCTAssertEqual(result!.nullableMapWithAnnotations, everything.nullableMapWithAnnotations) + XCTAssert(equalsDictionary(result!.nullableMapWithObject, everything.nullableMapWithObject)) expectation.fulfill() } diff --git a/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift index 4a70e4a536a..130d53b5c59 100644 --- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift @@ -14,6 +14,10 @@ import FlutterMacOS #error("Unsupported platform.") #endif +private func isNullish(_ value: Any?) -> Bool { + return value is NSNull || value == nil +} + private func wrapResult(_ result: Any?) -> [Any?] { return [result] } @@ -135,8 +139,8 @@ struct AllNullableTypes { static func fromList(_ list: [Any?]) -> AllNullableTypes? { let aNullableBool: Bool? = nilOrValue(list[0]) - let aNullableInt: Int64? = list[1] is NSNull ? nil : (list[1] is Int64? ? list[1] as! Int64? : Int64(list[1] as! Int32)) - let aNullableInt64: Int64? = list[2] is NSNull ? nil : (list[2] is Int64? ? list[2] as! Int64? : Int64(list[2] as! Int32)) + let aNullableInt: Int64? = isNullish(list[1]) ? nil : (list[1] is Int64? ? list[1] as! Int64? : Int64(list[1] as! Int32)) + let aNullableInt64: Int64? = isNullish(list[2]) ? nil : (list[2] is Int64? ? list[2] as! Int64? : Int64(list[2] as! Int32)) let aNullableDouble: Double? = nilOrValue(list[3]) let aNullableByteArray: FlutterStandardTypedData? = nilOrValue(list[4]) let aNullable4ByteArray: FlutterStandardTypedData? = nilOrValue(list[5]) @@ -332,6 +336,8 @@ protocol HostIntegrationCoreApi { func echo(_ aMap: [String?: Any?]) throws -> [String?: Any?] /// Returns the passed map to test nested class serialization and deserialization. func echo(_ wrapper: AllClassesWrapper) throws -> AllClassesWrapper + /// Returns the passed enum to test serialization and deserialization. + func echo(_ anEnum: AnEnum) throws -> AnEnum /// Returns the passed object, to test serialization and deserialization. func echo(_ everything: AllNullableTypes?) throws -> AllNullableTypes? /// Returns the inner `aString` value from the wrapped object, to test @@ -358,6 +364,7 @@ protocol HostIntegrationCoreApi { func echoNullable(_ aNullableList: [Any?]?) throws -> [Any?]? /// Returns the passed map, to test serialization and deserialization. func echoNullable(_ aNullableMap: [String?: Any?]?) throws -> [String?: Any?]? + func echoNullable(_ anEnum: AnEnum?) throws -> AnEnum? /// A no-op function taking no arguments and returning no value, to sanity /// test basic asynchronous calling. func noopAsync(completion: @escaping (Result) -> Void) @@ -373,10 +380,12 @@ protocol HostIntegrationCoreApi { func echoAsync(_ aUint8List: FlutterStandardTypedData, completion: @escaping (Result) -> Void) /// Returns the passed in generic Object asynchronously. func echoAsync(_ anObject: Any, completion: @escaping (Result) -> Void) - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. func echoAsync(_ aList: [Any?], completion: @escaping (Result<[Any?], Error>) -> Void) - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. func echoAsync(_ aMap: [String?: Any?], completion: @escaping (Result<[String?: Any?], Error>) -> Void) + /// Returns the passed enum, to test asynchronous serialization and deserialization. + func echoAsync(_ anEnum: AnEnum, completion: @escaping (Result) -> Void) /// Responds with an error from an async function returning a value. func throwAsyncError(completion: @escaping (Result) -> Void) /// Responds with an error from an async void function. @@ -399,14 +408,17 @@ protocol HostIntegrationCoreApi { func echoAsyncNullable(_ aUint8List: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) /// Returns the passed in generic Object asynchronously. func echoAsyncNullable(_ anObject: Any?, completion: @escaping (Result) -> Void) - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. func echoAsyncNullable(_ aList: [Any?]?, completion: @escaping (Result<[Any?]?, Error>) -> Void) - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. func echoAsyncNullable(_ aMap: [String?: Any?]?, completion: @escaping (Result<[String?: Any?]?, Error>) -> Void) + /// Returns the passed enum, to test asynchronous serialization and deserialization. + func echoAsyncNullable(_ anEnum: AnEnum?, completion: @escaping (Result) -> Void) func callFlutterNoop(completion: @escaping (Result) -> Void) func callFlutterThrowError(completion: @escaping (Result) -> Void) func callFlutterThrowErrorFromVoid(completion: @escaping (Result) -> Void) func callFlutterEcho(_ everything: AllTypes, completion: @escaping (Result) -> Void) + func callFlutterEcho(_ everything: AllNullableTypes?, completion: @escaping (Result) -> Void) func callFlutterSendMultipleNullableTypes(aBool aNullableBool: Bool?, anInt aNullableInt: Int64?, aString aNullableString: String?, completion: @escaping (Result) -> Void) func callFlutterEcho(_ aBool: Bool, completion: @escaping (Result) -> Void) func callFlutterEcho(_ anInt: Int64, completion: @escaping (Result) -> Void) @@ -415,6 +427,7 @@ protocol HostIntegrationCoreApi { func callFlutterEcho(_ aList: FlutterStandardTypedData, completion: @escaping (Result) -> Void) func callFlutterEcho(_ aList: [Any?], completion: @escaping (Result<[Any?], Error>) -> Void) func callFlutterEcho(_ aMap: [String?: Any?], completion: @escaping (Result<[String?: Any?], Error>) -> Void) + func callFlutterEcho(_ anEnum: AnEnum, completion: @escaping (Result) -> Void) func callFlutterEchoNullable(_ aBool: Bool?, completion: @escaping (Result) -> Void) func callFlutterEchoNullable(_ anInt: Int64?, completion: @escaping (Result) -> Void) func callFlutterEchoNullable(_ aDouble: Double?, completion: @escaping (Result) -> Void) @@ -422,6 +435,7 @@ protocol HostIntegrationCoreApi { func callFlutterEchoNullable(_ aList: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) func callFlutterEchoNullable(_ aList: [Any?]?, completion: @escaping (Result<[Any?]?, Error>) -> Void) func callFlutterEchoNullable(_ aMap: [String?: Any?]?, completion: @escaping (Result<[String?: Any?]?, Error>) -> Void) + func callFlutterNullableEcho(_ anEnum: AnEnum?, completion: @escaping (Result) -> Void) } /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. @@ -647,6 +661,22 @@ class HostIntegrationCoreApiSetup { } else { echoClassWrapperChannel.setMessageHandler(nil) } + /// Returns the passed enum to test serialization and deserialization. + let echoEnumChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoEnum", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + echoEnumChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let anEnumArg = AnEnum(rawValue: args[0] as! Int)! + do { + let result = try api.echo(anEnumArg) + reply(wrapResult(result.rawValue)) + } catch { + reply(wrapError(error)) + } + } + } else { + echoEnumChannel.setMessageHandler(nil) + } /// Returns the passed object, to test serialization and deserialization. let echoAllNullableTypesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAllNullableTypes", binaryMessenger: binaryMessenger, codec: codec) if let api = api { @@ -703,7 +733,7 @@ class HostIntegrationCoreApiSetup { sendMultipleNullableTypesChannel.setMessageHandler { message, reply in let args = message as! [Any?] let aNullableBoolArg: Bool? = nilOrValue(args[0]) - let aNullableIntArg: Int64? = args[1] is NSNull ? nil : (args[1] is Int64? ? args[1] as! Int64? : Int64(args[1] as! Int32)) + let aNullableIntArg: Int64? = isNullish(args[1]) ? nil : (args[1] is Int64? ? args[1] as! Int64? : Int64(args[1] as! Int32)) let aNullableStringArg: String? = nilOrValue(args[2]) do { let result = try api.sendMultipleNullableTypes(aBool: aNullableBoolArg, anInt: aNullableIntArg, aString: aNullableStringArg) @@ -720,7 +750,7 @@ class HostIntegrationCoreApiSetup { if let api = api { echoNullableIntChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let aNullableIntArg: Int64? = args[0] is NSNull ? nil : (args[0] is Int64? ? args[0] as! Int64? : Int64(args[0] as! Int32)) + let aNullableIntArg: Int64? = isNullish(args[0]) ? nil : (args[0] is Int64? ? args[0] as! Int64? : Int64(args[0] as! Int32)) do { let result = try api.echo(aNullableIntArg) reply(wrapResult(result)) @@ -843,6 +873,21 @@ class HostIntegrationCoreApiSetup { } else { echoNullableMapChannel.setMessageHandler(nil) } + let echoNullableEnumChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoNullableEnum", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + echoNullableEnumChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let anEnumArg: AnEnum? = isNullish(args[0]) ? nil : AnEnum(rawValue: args[0] as! Int)! + do { + let result = try api.echoNullable(anEnumArg) + reply(wrapResult(result?.rawValue)) + } catch { + reply(wrapError(error)) + } + } + } else { + echoNullableEnumChannel.setMessageHandler(nil) + } /// A no-op function taking no arguments and returning no value, to sanity /// test basic asynchronous calling. let noopAsyncChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.noopAsync", binaryMessenger: binaryMessenger, codec: codec) @@ -968,7 +1013,7 @@ class HostIntegrationCoreApiSetup { } else { echoAsyncObjectChannel.setMessageHandler(nil) } - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. let echoAsyncListChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncList", binaryMessenger: binaryMessenger, codec: codec) if let api = api { echoAsyncListChannel.setMessageHandler { message, reply in @@ -986,7 +1031,7 @@ class HostIntegrationCoreApiSetup { } else { echoAsyncListChannel.setMessageHandler(nil) } - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. let echoAsyncMapChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncMap", binaryMessenger: binaryMessenger, codec: codec) if let api = api { echoAsyncMapChannel.setMessageHandler { message, reply in @@ -1004,6 +1049,24 @@ class HostIntegrationCoreApiSetup { } else { echoAsyncMapChannel.setMessageHandler(nil) } + /// Returns the passed enum, to test asynchronous serialization and deserialization. + let echoAsyncEnumChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncEnum", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + echoAsyncEnumChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let anEnumArg = AnEnum(rawValue: args[0] as! Int)! + api.echoAsync(anEnumArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res.rawValue)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + echoAsyncEnumChannel.setMessageHandler(nil) + } /// Responds with an error from an async function returning a value. let throwAsyncErrorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.throwAsyncError", binaryMessenger: binaryMessenger, codec: codec) if let api = api { @@ -1093,7 +1156,7 @@ class HostIntegrationCoreApiSetup { if let api = api { echoAsyncNullableIntChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let anIntArg: Int64? = args[0] is NSNull ? nil : (args[0] is Int64? ? args[0] as! Int64? : Int64(args[0] as! Int32)) + let anIntArg: Int64? = isNullish(args[0]) ? nil : (args[0] is Int64? ? args[0] as! Int64? : Int64(args[0] as! Int32)) api.echoAsyncNullable(anIntArg) { result in switch result { case .success(let res): @@ -1196,7 +1259,7 @@ class HostIntegrationCoreApiSetup { } else { echoAsyncNullableObjectChannel.setMessageHandler(nil) } - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. let echoAsyncNullableListChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncNullableList", binaryMessenger: binaryMessenger, codec: codec) if let api = api { echoAsyncNullableListChannel.setMessageHandler { message, reply in @@ -1214,7 +1277,7 @@ class HostIntegrationCoreApiSetup { } else { echoAsyncNullableListChannel.setMessageHandler(nil) } - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. let echoAsyncNullableMapChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncNullableMap", binaryMessenger: binaryMessenger, codec: codec) if let api = api { echoAsyncNullableMapChannel.setMessageHandler { message, reply in @@ -1232,6 +1295,24 @@ class HostIntegrationCoreApiSetup { } else { echoAsyncNullableMapChannel.setMessageHandler(nil) } + /// Returns the passed enum, to test asynchronous serialization and deserialization. + let echoAsyncNullableEnumChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncNullableEnum", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + echoAsyncNullableEnumChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let anEnumArg: AnEnum? = isNullish(args[0]) ? nil : AnEnum(rawValue: args[0] as! Int)! + api.echoAsyncNullable(anEnumArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res?.rawValue)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + echoAsyncNullableEnumChannel.setMessageHandler(nil) + } let callFlutterNoopChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterNoop", binaryMessenger: binaryMessenger, codec: codec) if let api = api { callFlutterNoopChannel.setMessageHandler { _, reply in @@ -1294,12 +1375,29 @@ class HostIntegrationCoreApiSetup { } else { callFlutterEchoAllTypesChannel.setMessageHandler(nil) } + let callFlutterEchoAllNullableTypesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoAllNullableTypes", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + callFlutterEchoAllNullableTypesChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let everythingArg: AllNullableTypes? = nilOrValue(args[0]) + api.callFlutterEcho(everythingArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + callFlutterEchoAllNullableTypesChannel.setMessageHandler(nil) + } let callFlutterSendMultipleNullableTypesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterSendMultipleNullableTypes", binaryMessenger: binaryMessenger, codec: codec) if let api = api { callFlutterSendMultipleNullableTypesChannel.setMessageHandler { message, reply in let args = message as! [Any?] let aNullableBoolArg: Bool? = nilOrValue(args[0]) - let aNullableIntArg: Int64? = args[1] is NSNull ? nil : (args[1] is Int64? ? args[1] as! Int64? : Int64(args[1] as! Int32)) + let aNullableIntArg: Int64? = isNullish(args[1]) ? nil : (args[1] is Int64? ? args[1] as! Int64? : Int64(args[1] as! Int32)) let aNullableStringArg: String? = nilOrValue(args[2]) api.callFlutterSendMultipleNullableTypes(aBool: aNullableBoolArg, anInt: aNullableIntArg, aString: aNullableStringArg) { result in switch result { @@ -1432,6 +1530,23 @@ class HostIntegrationCoreApiSetup { } else { callFlutterEchoMapChannel.setMessageHandler(nil) } + let callFlutterEchoEnumChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoEnum", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + callFlutterEchoEnumChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let anEnumArg = AnEnum(rawValue: args[0] as! Int)! + api.callFlutterEcho(anEnumArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res.rawValue)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + callFlutterEchoEnumChannel.setMessageHandler(nil) + } let callFlutterEchoNullableBoolChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoNullableBool", binaryMessenger: binaryMessenger, codec: codec) if let api = api { callFlutterEchoNullableBoolChannel.setMessageHandler { message, reply in @@ -1453,7 +1568,7 @@ class HostIntegrationCoreApiSetup { if let api = api { callFlutterEchoNullableIntChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let anIntArg: Int64? = args[0] is NSNull ? nil : (args[0] is Int64? ? args[0] as! Int64? : Int64(args[0] as! Int32)) + let anIntArg: Int64? = isNullish(args[0]) ? nil : (args[0] is Int64? ? args[0] as! Int64? : Int64(args[0] as! Int32)) api.callFlutterEchoNullable(anIntArg) { result in switch result { case .success(let res): @@ -1551,6 +1666,23 @@ class HostIntegrationCoreApiSetup { } else { callFlutterEchoNullableMapChannel.setMessageHandler(nil) } + let callFlutterEchoNullableEnumChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoNullableEnum", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + callFlutterEchoNullableEnumChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let anEnumArg: AnEnum? = isNullish(args[0]) ? nil : AnEnum(rawValue: args[0] as! Int)! + api.callFlutterNullableEcho(anEnumArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res?.rawValue)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + callFlutterEchoNullableEnumChannel.setMessageHandler(nil) + } } } private class FlutterIntegrationCoreApiCodecReader: FlutterStandardReader { @@ -1648,10 +1780,10 @@ class FlutterIntegrationCoreApi { } } /// Returns the passed object, to test serialization and deserialization. - func echoNullable(_ everythingArg: AllNullableTypes, completion: @escaping (AllNullableTypes) -> Void) { + func echoNullable(_ everythingArg: AllNullableTypes?, completion: @escaping (AllNullableTypes?) -> Void) { let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoAllNullableTypes", binaryMessenger: binaryMessenger, codec: codec) channel.sendMessage([everythingArg] as [Any?]) { response in - let result = response as! AllNullableTypes + let result: AllNullableTypes? = nilOrValue(response) completion(result) } } @@ -1721,6 +1853,14 @@ class FlutterIntegrationCoreApi { completion(result) } } + /// Returns the passed enum to test serialization and deserialization. + func echo(_ anEnumArg: AnEnum, completion: @escaping (AnEnum) -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoEnum", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([anEnumArg.rawValue] as [Any?]) { response in + let result = AnEnum(rawValue: response as! Int)! + completion(result) + } + } /// Returns the passed boolean, to test serialization and deserialization. func echoNullable(_ aBoolArg: Bool?, completion: @escaping (Bool?) -> Void) { let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoNullableBool", binaryMessenger: binaryMessenger, codec: codec) @@ -1733,7 +1873,7 @@ class FlutterIntegrationCoreApi { func echoNullable(_ anIntArg: Int64?, completion: @escaping (Int64?) -> Void) { let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoNullableInt", binaryMessenger: binaryMessenger, codec: codec) channel.sendMessage([anIntArg] as [Any?]) { response in - let result: Int64? = response is NSNull ? nil : (response is Int64? ? response as! Int64? : Int64(response as! Int32)) + let result: Int64? = isNullish(response) ? nil : (response is Int64? ? response as! Int64? : Int64(response as! Int32)) completion(result) } } @@ -1777,6 +1917,14 @@ class FlutterIntegrationCoreApi { completion(result) } } + /// Returns the passed enum to test serialization and deserialization. + func echoNullable(_ anEnumArg: AnEnum?, completion: @escaping (AnEnum?) -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoNullableEnum", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([anEnumArg?.rawValue] as [Any?]) { response in + let result: AnEnum? = isNullish(response) ? nil : AnEnum(rawValue: response as! Int)! + completion(result) + } + } /// A no-op function taking no arguments and returning no value, to sanity /// test basic asynchronous calling. func noopAsync(completion: @escaping () -> Void) { diff --git a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift index 315c86c81e2..201b1136274 100644 --- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift +++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift @@ -81,9 +81,13 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { return aMap } - func echo(_ wrapper: AllClassesWrapper) throws -> AllClassesWrapper { + func echo(_ wrapper: AllClassesWrapper) throws -> AllClassesWrapper { return wrapper - } + } + + func echo(_ anEnum: AnEnum) throws -> AnEnum { + return anEnum + } func extractNestedNullableString(from wrapper: AllClassesWrapper) -> String? { return wrapper.allNullableTypes.aNullableString; @@ -130,6 +134,10 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { return aNullableMap } + func echoNullable(_ anEnum: AnEnum?) throws -> AnEnum? { + return anEnum + } + func noopAsync(completion: @escaping (Result) -> Void) { completion(.success(Void())) } @@ -186,6 +194,10 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { completion(.success(aMap)) } + func echoAsync(_ anEnum: AnEnum, completion: @escaping (Result) -> Void) { + completion(.success(anEnum)) + } + func echoAsyncNullable(_ anInt: Int64?, completion: @escaping (Result) -> Void) { completion(.success(anInt)) } @@ -218,6 +230,10 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { completion(.success(aMap)) } + func echoAsyncNullable(_ anEnum: AnEnum?, completion: @escaping (Result) -> Void) { + completion(.success(anEnum)) + } + func callFlutterNoop(completion: @escaping (Result) -> Void) { flutterAPI.noop() { completion(.success(Void())) @@ -240,6 +256,12 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { } } + func callFlutterEcho(_ everything: AllNullableTypes?, completion: @escaping (Result) -> Void) { + flutterAPI.echoNullable(everything) { + completion(.success($0)) + } + } + func callFlutterSendMultipleNullableTypes( aBool aNullableBool: Bool?, anInt aNullableInt: Int64?, @@ -297,6 +319,12 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { } } + func callFlutterEcho(_ anEnum: AnEnum, completion: @escaping (Result) -> Void) { + flutterAPI.echo(anEnum) { + completion(.success($0)) + } + } + func callFlutterEchoNullable(_ aBool: Bool?, completion: @escaping (Result) -> Void) { flutterAPI.echoNullable(aBool) { completion(.success($0)) @@ -338,4 +366,10 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { completion(.success($0)) } } + + func callFlutterNullableEcho(_ anEnum: AnEnum?, completion: @escaping (Result) -> Void) { + flutterAPI.echoNullable(anEnum) { + completion(.success($0)) + } + } } diff --git a/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift index 4a70e4a536a..130d53b5c59 100644 --- a/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift @@ -14,6 +14,10 @@ import FlutterMacOS #error("Unsupported platform.") #endif +private func isNullish(_ value: Any?) -> Bool { + return value is NSNull || value == nil +} + private func wrapResult(_ result: Any?) -> [Any?] { return [result] } @@ -135,8 +139,8 @@ struct AllNullableTypes { static func fromList(_ list: [Any?]) -> AllNullableTypes? { let aNullableBool: Bool? = nilOrValue(list[0]) - let aNullableInt: Int64? = list[1] is NSNull ? nil : (list[1] is Int64? ? list[1] as! Int64? : Int64(list[1] as! Int32)) - let aNullableInt64: Int64? = list[2] is NSNull ? nil : (list[2] is Int64? ? list[2] as! Int64? : Int64(list[2] as! Int32)) + let aNullableInt: Int64? = isNullish(list[1]) ? nil : (list[1] is Int64? ? list[1] as! Int64? : Int64(list[1] as! Int32)) + let aNullableInt64: Int64? = isNullish(list[2]) ? nil : (list[2] is Int64? ? list[2] as! Int64? : Int64(list[2] as! Int32)) let aNullableDouble: Double? = nilOrValue(list[3]) let aNullableByteArray: FlutterStandardTypedData? = nilOrValue(list[4]) let aNullable4ByteArray: FlutterStandardTypedData? = nilOrValue(list[5]) @@ -332,6 +336,8 @@ protocol HostIntegrationCoreApi { func echo(_ aMap: [String?: Any?]) throws -> [String?: Any?] /// Returns the passed map to test nested class serialization and deserialization. func echo(_ wrapper: AllClassesWrapper) throws -> AllClassesWrapper + /// Returns the passed enum to test serialization and deserialization. + func echo(_ anEnum: AnEnum) throws -> AnEnum /// Returns the passed object, to test serialization and deserialization. func echo(_ everything: AllNullableTypes?) throws -> AllNullableTypes? /// Returns the inner `aString` value from the wrapped object, to test @@ -358,6 +364,7 @@ protocol HostIntegrationCoreApi { func echoNullable(_ aNullableList: [Any?]?) throws -> [Any?]? /// Returns the passed map, to test serialization and deserialization. func echoNullable(_ aNullableMap: [String?: Any?]?) throws -> [String?: Any?]? + func echoNullable(_ anEnum: AnEnum?) throws -> AnEnum? /// A no-op function taking no arguments and returning no value, to sanity /// test basic asynchronous calling. func noopAsync(completion: @escaping (Result) -> Void) @@ -373,10 +380,12 @@ protocol HostIntegrationCoreApi { func echoAsync(_ aUint8List: FlutterStandardTypedData, completion: @escaping (Result) -> Void) /// Returns the passed in generic Object asynchronously. func echoAsync(_ anObject: Any, completion: @escaping (Result) -> Void) - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. func echoAsync(_ aList: [Any?], completion: @escaping (Result<[Any?], Error>) -> Void) - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. func echoAsync(_ aMap: [String?: Any?], completion: @escaping (Result<[String?: Any?], Error>) -> Void) + /// Returns the passed enum, to test asynchronous serialization and deserialization. + func echoAsync(_ anEnum: AnEnum, completion: @escaping (Result) -> Void) /// Responds with an error from an async function returning a value. func throwAsyncError(completion: @escaping (Result) -> Void) /// Responds with an error from an async void function. @@ -399,14 +408,17 @@ protocol HostIntegrationCoreApi { func echoAsyncNullable(_ aUint8List: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) /// Returns the passed in generic Object asynchronously. func echoAsyncNullable(_ anObject: Any?, completion: @escaping (Result) -> Void) - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. func echoAsyncNullable(_ aList: [Any?]?, completion: @escaping (Result<[Any?]?, Error>) -> Void) - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. func echoAsyncNullable(_ aMap: [String?: Any?]?, completion: @escaping (Result<[String?: Any?]?, Error>) -> Void) + /// Returns the passed enum, to test asynchronous serialization and deserialization. + func echoAsyncNullable(_ anEnum: AnEnum?, completion: @escaping (Result) -> Void) func callFlutterNoop(completion: @escaping (Result) -> Void) func callFlutterThrowError(completion: @escaping (Result) -> Void) func callFlutterThrowErrorFromVoid(completion: @escaping (Result) -> Void) func callFlutterEcho(_ everything: AllTypes, completion: @escaping (Result) -> Void) + func callFlutterEcho(_ everything: AllNullableTypes?, completion: @escaping (Result) -> Void) func callFlutterSendMultipleNullableTypes(aBool aNullableBool: Bool?, anInt aNullableInt: Int64?, aString aNullableString: String?, completion: @escaping (Result) -> Void) func callFlutterEcho(_ aBool: Bool, completion: @escaping (Result) -> Void) func callFlutterEcho(_ anInt: Int64, completion: @escaping (Result) -> Void) @@ -415,6 +427,7 @@ protocol HostIntegrationCoreApi { func callFlutterEcho(_ aList: FlutterStandardTypedData, completion: @escaping (Result) -> Void) func callFlutterEcho(_ aList: [Any?], completion: @escaping (Result<[Any?], Error>) -> Void) func callFlutterEcho(_ aMap: [String?: Any?], completion: @escaping (Result<[String?: Any?], Error>) -> Void) + func callFlutterEcho(_ anEnum: AnEnum, completion: @escaping (Result) -> Void) func callFlutterEchoNullable(_ aBool: Bool?, completion: @escaping (Result) -> Void) func callFlutterEchoNullable(_ anInt: Int64?, completion: @escaping (Result) -> Void) func callFlutterEchoNullable(_ aDouble: Double?, completion: @escaping (Result) -> Void) @@ -422,6 +435,7 @@ protocol HostIntegrationCoreApi { func callFlutterEchoNullable(_ aList: FlutterStandardTypedData?, completion: @escaping (Result) -> Void) func callFlutterEchoNullable(_ aList: [Any?]?, completion: @escaping (Result<[Any?]?, Error>) -> Void) func callFlutterEchoNullable(_ aMap: [String?: Any?]?, completion: @escaping (Result<[String?: Any?]?, Error>) -> Void) + func callFlutterNullableEcho(_ anEnum: AnEnum?, completion: @escaping (Result) -> Void) } /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. @@ -647,6 +661,22 @@ class HostIntegrationCoreApiSetup { } else { echoClassWrapperChannel.setMessageHandler(nil) } + /// Returns the passed enum to test serialization and deserialization. + let echoEnumChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoEnum", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + echoEnumChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let anEnumArg = AnEnum(rawValue: args[0] as! Int)! + do { + let result = try api.echo(anEnumArg) + reply(wrapResult(result.rawValue)) + } catch { + reply(wrapError(error)) + } + } + } else { + echoEnumChannel.setMessageHandler(nil) + } /// Returns the passed object, to test serialization and deserialization. let echoAllNullableTypesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAllNullableTypes", binaryMessenger: binaryMessenger, codec: codec) if let api = api { @@ -703,7 +733,7 @@ class HostIntegrationCoreApiSetup { sendMultipleNullableTypesChannel.setMessageHandler { message, reply in let args = message as! [Any?] let aNullableBoolArg: Bool? = nilOrValue(args[0]) - let aNullableIntArg: Int64? = args[1] is NSNull ? nil : (args[1] is Int64? ? args[1] as! Int64? : Int64(args[1] as! Int32)) + let aNullableIntArg: Int64? = isNullish(args[1]) ? nil : (args[1] is Int64? ? args[1] as! Int64? : Int64(args[1] as! Int32)) let aNullableStringArg: String? = nilOrValue(args[2]) do { let result = try api.sendMultipleNullableTypes(aBool: aNullableBoolArg, anInt: aNullableIntArg, aString: aNullableStringArg) @@ -720,7 +750,7 @@ class HostIntegrationCoreApiSetup { if let api = api { echoNullableIntChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let aNullableIntArg: Int64? = args[0] is NSNull ? nil : (args[0] is Int64? ? args[0] as! Int64? : Int64(args[0] as! Int32)) + let aNullableIntArg: Int64? = isNullish(args[0]) ? nil : (args[0] is Int64? ? args[0] as! Int64? : Int64(args[0] as! Int32)) do { let result = try api.echo(aNullableIntArg) reply(wrapResult(result)) @@ -843,6 +873,21 @@ class HostIntegrationCoreApiSetup { } else { echoNullableMapChannel.setMessageHandler(nil) } + let echoNullableEnumChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoNullableEnum", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + echoNullableEnumChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let anEnumArg: AnEnum? = isNullish(args[0]) ? nil : AnEnum(rawValue: args[0] as! Int)! + do { + let result = try api.echoNullable(anEnumArg) + reply(wrapResult(result?.rawValue)) + } catch { + reply(wrapError(error)) + } + } + } else { + echoNullableEnumChannel.setMessageHandler(nil) + } /// A no-op function taking no arguments and returning no value, to sanity /// test basic asynchronous calling. let noopAsyncChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.noopAsync", binaryMessenger: binaryMessenger, codec: codec) @@ -968,7 +1013,7 @@ class HostIntegrationCoreApiSetup { } else { echoAsyncObjectChannel.setMessageHandler(nil) } - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. let echoAsyncListChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncList", binaryMessenger: binaryMessenger, codec: codec) if let api = api { echoAsyncListChannel.setMessageHandler { message, reply in @@ -986,7 +1031,7 @@ class HostIntegrationCoreApiSetup { } else { echoAsyncListChannel.setMessageHandler(nil) } - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. let echoAsyncMapChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncMap", binaryMessenger: binaryMessenger, codec: codec) if let api = api { echoAsyncMapChannel.setMessageHandler { message, reply in @@ -1004,6 +1049,24 @@ class HostIntegrationCoreApiSetup { } else { echoAsyncMapChannel.setMessageHandler(nil) } + /// Returns the passed enum, to test asynchronous serialization and deserialization. + let echoAsyncEnumChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncEnum", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + echoAsyncEnumChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let anEnumArg = AnEnum(rawValue: args[0] as! Int)! + api.echoAsync(anEnumArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res.rawValue)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + echoAsyncEnumChannel.setMessageHandler(nil) + } /// Responds with an error from an async function returning a value. let throwAsyncErrorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.throwAsyncError", binaryMessenger: binaryMessenger, codec: codec) if let api = api { @@ -1093,7 +1156,7 @@ class HostIntegrationCoreApiSetup { if let api = api { echoAsyncNullableIntChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let anIntArg: Int64? = args[0] is NSNull ? nil : (args[0] is Int64? ? args[0] as! Int64? : Int64(args[0] as! Int32)) + let anIntArg: Int64? = isNullish(args[0]) ? nil : (args[0] is Int64? ? args[0] as! Int64? : Int64(args[0] as! Int32)) api.echoAsyncNullable(anIntArg) { result in switch result { case .success(let res): @@ -1196,7 +1259,7 @@ class HostIntegrationCoreApiSetup { } else { echoAsyncNullableObjectChannel.setMessageHandler(nil) } - /// Returns the passed list, to test serialization and deserialization asynchronously. + /// Returns the passed list, to test asynchronous serialization and deserialization. let echoAsyncNullableListChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncNullableList", binaryMessenger: binaryMessenger, codec: codec) if let api = api { echoAsyncNullableListChannel.setMessageHandler { message, reply in @@ -1214,7 +1277,7 @@ class HostIntegrationCoreApiSetup { } else { echoAsyncNullableListChannel.setMessageHandler(nil) } - /// Returns the passed map, to test serialization and deserialization asynchronously. + /// Returns the passed map, to test asynchronous serialization and deserialization. let echoAsyncNullableMapChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncNullableMap", binaryMessenger: binaryMessenger, codec: codec) if let api = api { echoAsyncNullableMapChannel.setMessageHandler { message, reply in @@ -1232,6 +1295,24 @@ class HostIntegrationCoreApiSetup { } else { echoAsyncNullableMapChannel.setMessageHandler(nil) } + /// Returns the passed enum, to test asynchronous serialization and deserialization. + let echoAsyncNullableEnumChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.echoAsyncNullableEnum", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + echoAsyncNullableEnumChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let anEnumArg: AnEnum? = isNullish(args[0]) ? nil : AnEnum(rawValue: args[0] as! Int)! + api.echoAsyncNullable(anEnumArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res?.rawValue)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + echoAsyncNullableEnumChannel.setMessageHandler(nil) + } let callFlutterNoopChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterNoop", binaryMessenger: binaryMessenger, codec: codec) if let api = api { callFlutterNoopChannel.setMessageHandler { _, reply in @@ -1294,12 +1375,29 @@ class HostIntegrationCoreApiSetup { } else { callFlutterEchoAllTypesChannel.setMessageHandler(nil) } + let callFlutterEchoAllNullableTypesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoAllNullableTypes", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + callFlutterEchoAllNullableTypesChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let everythingArg: AllNullableTypes? = nilOrValue(args[0]) + api.callFlutterEcho(everythingArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + callFlutterEchoAllNullableTypesChannel.setMessageHandler(nil) + } let callFlutterSendMultipleNullableTypesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterSendMultipleNullableTypes", binaryMessenger: binaryMessenger, codec: codec) if let api = api { callFlutterSendMultipleNullableTypesChannel.setMessageHandler { message, reply in let args = message as! [Any?] let aNullableBoolArg: Bool? = nilOrValue(args[0]) - let aNullableIntArg: Int64? = args[1] is NSNull ? nil : (args[1] is Int64? ? args[1] as! Int64? : Int64(args[1] as! Int32)) + let aNullableIntArg: Int64? = isNullish(args[1]) ? nil : (args[1] is Int64? ? args[1] as! Int64? : Int64(args[1] as! Int32)) let aNullableStringArg: String? = nilOrValue(args[2]) api.callFlutterSendMultipleNullableTypes(aBool: aNullableBoolArg, anInt: aNullableIntArg, aString: aNullableStringArg) { result in switch result { @@ -1432,6 +1530,23 @@ class HostIntegrationCoreApiSetup { } else { callFlutterEchoMapChannel.setMessageHandler(nil) } + let callFlutterEchoEnumChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoEnum", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + callFlutterEchoEnumChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let anEnumArg = AnEnum(rawValue: args[0] as! Int)! + api.callFlutterEcho(anEnumArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res.rawValue)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + callFlutterEchoEnumChannel.setMessageHandler(nil) + } let callFlutterEchoNullableBoolChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoNullableBool", binaryMessenger: binaryMessenger, codec: codec) if let api = api { callFlutterEchoNullableBoolChannel.setMessageHandler { message, reply in @@ -1453,7 +1568,7 @@ class HostIntegrationCoreApiSetup { if let api = api { callFlutterEchoNullableIntChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let anIntArg: Int64? = args[0] is NSNull ? nil : (args[0] is Int64? ? args[0] as! Int64? : Int64(args[0] as! Int32)) + let anIntArg: Int64? = isNullish(args[0]) ? nil : (args[0] is Int64? ? args[0] as! Int64? : Int64(args[0] as! Int32)) api.callFlutterEchoNullable(anIntArg) { result in switch result { case .success(let res): @@ -1551,6 +1666,23 @@ class HostIntegrationCoreApiSetup { } else { callFlutterEchoNullableMapChannel.setMessageHandler(nil) } + let callFlutterEchoNullableEnumChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterEchoNullableEnum", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + callFlutterEchoNullableEnumChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let anEnumArg: AnEnum? = isNullish(args[0]) ? nil : AnEnum(rawValue: args[0] as! Int)! + api.callFlutterNullableEcho(anEnumArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res?.rawValue)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + callFlutterEchoNullableEnumChannel.setMessageHandler(nil) + } } } private class FlutterIntegrationCoreApiCodecReader: FlutterStandardReader { @@ -1648,10 +1780,10 @@ class FlutterIntegrationCoreApi { } } /// Returns the passed object, to test serialization and deserialization. - func echoNullable(_ everythingArg: AllNullableTypes, completion: @escaping (AllNullableTypes) -> Void) { + func echoNullable(_ everythingArg: AllNullableTypes?, completion: @escaping (AllNullableTypes?) -> Void) { let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoAllNullableTypes", binaryMessenger: binaryMessenger, codec: codec) channel.sendMessage([everythingArg] as [Any?]) { response in - let result = response as! AllNullableTypes + let result: AllNullableTypes? = nilOrValue(response) completion(result) } } @@ -1721,6 +1853,14 @@ class FlutterIntegrationCoreApi { completion(result) } } + /// Returns the passed enum to test serialization and deserialization. + func echo(_ anEnumArg: AnEnum, completion: @escaping (AnEnum) -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoEnum", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([anEnumArg.rawValue] as [Any?]) { response in + let result = AnEnum(rawValue: response as! Int)! + completion(result) + } + } /// Returns the passed boolean, to test serialization and deserialization. func echoNullable(_ aBoolArg: Bool?, completion: @escaping (Bool?) -> Void) { let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoNullableBool", binaryMessenger: binaryMessenger, codec: codec) @@ -1733,7 +1873,7 @@ class FlutterIntegrationCoreApi { func echoNullable(_ anIntArg: Int64?, completion: @escaping (Int64?) -> Void) { let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoNullableInt", binaryMessenger: binaryMessenger, codec: codec) channel.sendMessage([anIntArg] as [Any?]) { response in - let result: Int64? = response is NSNull ? nil : (response is Int64? ? response as! Int64? : Int64(response as! Int32)) + let result: Int64? = isNullish(response) ? nil : (response is Int64? ? response as! Int64? : Int64(response as! Int32)) completion(result) } } @@ -1777,6 +1917,14 @@ class FlutterIntegrationCoreApi { completion(result) } } + /// Returns the passed enum to test serialization and deserialization. + func echoNullable(_ anEnumArg: AnEnum?, completion: @escaping (AnEnum?) -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi.echoNullableEnum", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([anEnumArg?.rawValue] as [Any?]) { response in + let result: AnEnum? = isNullish(response) ? nil : AnEnum(rawValue: response as! Int)! + completion(result) + } + } /// A no-op function taking no arguments and returning no value, to sanity /// test basic asynchronous calling. func noopAsync(completion: @escaping () -> Void) { diff --git a/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift b/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift index d5f27f6aea0..a06f7a5fd10 100644 --- a/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift +++ b/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift @@ -24,6 +24,7 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { } // MARK: HostIntegrationCoreApi implementation + func noop() { } @@ -80,9 +81,13 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { return aMap } - func echo(_ wrapper: AllClassesWrapper) throws -> AllClassesWrapper { + func echo(_ wrapper: AllClassesWrapper) throws -> AllClassesWrapper { return wrapper - } + } + + func echo(_ anEnum: AnEnum) throws -> AnEnum { + return anEnum + } func extractNestedNullableString(from wrapper: AllClassesWrapper) -> String? { return wrapper.allNullableTypes.aNullableString; @@ -129,6 +134,10 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { return aNullableMap } + func echoNullable(_ anEnum: AnEnum?) throws -> AnEnum? { + return anEnum + } + func noopAsync(completion: @escaping (Result) -> Void) { completion(.success(Void())) } @@ -185,6 +194,10 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { completion(.success(aMap)) } + func echoAsync(_ anEnum: AnEnum, completion: @escaping (Result) -> Void) { + completion(.success(anEnum)) + } + func echoAsyncNullable(_ anInt: Int64?, completion: @escaping (Result) -> Void) { completion(.success(anInt)) } @@ -217,6 +230,10 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { completion(.success(aMap)) } + func echoAsyncNullable(_ anEnum: AnEnum?, completion: @escaping (Result) -> Void) { + completion(.success(anEnum)) + } + func callFlutterNoop(completion: @escaping (Result) -> Void) { flutterAPI.noop() { completion(.success(Void())) @@ -239,6 +256,12 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { } } + func callFlutterEcho(_ everything: AllNullableTypes?, completion: @escaping (Result) -> Void) { + flutterAPI.echoNullable(everything) { + completion(.success($0)) + } + } + func callFlutterSendMultipleNullableTypes( aBool aNullableBool: Bool?, anInt aNullableInt: Int64?, @@ -296,6 +319,12 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { } } + func callFlutterEcho(_ anEnum: AnEnum, completion: @escaping (Result) -> Void) { + flutterAPI.echo(anEnum) { + completion(.success($0)) + } + } + func callFlutterEchoNullable(_ aBool: Bool?, completion: @escaping (Result) -> Void) { flutterAPI.echoNullable(aBool) { completion(.success($0)) @@ -337,4 +366,10 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { completion(.success($0)) } } -} \ No newline at end of file + + func callFlutterNullableEcho(_ anEnum: AnEnum?, completion: @escaping (Result) -> Void) { + flutterAPI.echoNullable(anEnum) { + completion(.success($0)) + } + } +} diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp index 469250078d7..3ef10d1f2d2 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp @@ -1207,6 +1207,42 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, channel->SetMessageHandler(nullptr); } } + { + auto channel = std::make_unique>( + binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "echoEnum", + &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_an_enum_arg = args.at(0); + if (encodable_an_enum_arg.IsNull()) { + reply(WrapError("an_enum_arg unexpectedly null.")); + return; + } + const AnEnum& an_enum_arg = + (AnEnum)encodable_an_enum_arg.LongValue(); + ErrorOr output = api->EchoEnum(an_enum_arg); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back( + EncodableValue((int)std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } { auto channel = std::make_unique>( binary_messenger, @@ -1679,6 +1715,51 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, channel->SetMessageHandler(nullptr); } } + { + auto channel = std::make_unique>( + binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "echoNullableEnum", + &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_an_enum_arg = args.at(0); + const int64_t an_enum_arg_value = + encodable_an_enum_arg.IsNull() + ? 0 + : encodable_an_enum_arg.LongValue(); + const auto an_enum_arg = + encodable_an_enum_arg.IsNull() + ? std::nullopt + : std::make_optional( + static_cast(an_enum_arg_value)); + ErrorOr> output = api->EchoNullableEnum( + an_enum_arg ? &(*an_enum_arg) : nullptr); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + auto output_optional = std::move(output).TakeValue(); + if (output_optional) { + wrapped.push_back( + EncodableValue((int)std::move(output_optional).value())); + } else { + wrapped.push_back(EncodableValue()); + } + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } { auto channel = std::make_unique>( binary_messenger, @@ -2007,6 +2088,44 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, channel->SetMessageHandler(nullptr); } } + { + auto channel = std::make_unique>( + binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "echoAsyncEnum", + &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_an_enum_arg = args.at(0); + if (encodable_an_enum_arg.IsNull()) { + reply(WrapError("an_enum_arg unexpectedly null.")); + return; + } + const AnEnum& an_enum_arg = + (AnEnum)encodable_an_enum_arg.LongValue(); + api->EchoAsyncEnum( + an_enum_arg, [reply](ErrorOr&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back( + EncodableValue((int)std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } { auto channel = std::make_unique>( binary_messenger, @@ -2508,6 +2627,53 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, channel->SetMessageHandler(nullptr); } } + { + auto channel = std::make_unique>( + binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "echoAsyncNullableEnum", + &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_an_enum_arg = args.at(0); + const int64_t an_enum_arg_value = + encodable_an_enum_arg.IsNull() + ? 0 + : encodable_an_enum_arg.LongValue(); + const auto an_enum_arg = + encodable_an_enum_arg.IsNull() + ? std::nullopt + : std::make_optional( + static_cast(an_enum_arg_value)); + api->EchoAsyncNullableEnum( + an_enum_arg ? &(*an_enum_arg) : nullptr, + [reply](ErrorOr>&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + auto output_optional = std::move(output).TakeValue(); + if (output_optional) { + wrapped.push_back(EncodableValue( + (int)std::move(output_optional).value())); + } else { + wrapped.push_back(EncodableValue()); + } + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } { auto channel = std::make_unique>( binary_messenger, @@ -2639,6 +2805,48 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, channel->SetMessageHandler(nullptr); } } + { + auto channel = std::make_unique>( + binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "callFlutterEchoAllNullableTypes", + &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_everything_arg = args.at(0); + const auto* everything_arg = + &(std::any_cast( + std::get( + encodable_everything_arg))); + api->CallFlutterEchoAllNullableTypes( + everything_arg, + [reply](ErrorOr>&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + auto output_optional = std::move(output).TakeValue(); + if (output_optional) { + wrapped.push_back(CustomEncodableValue( + std::move(output_optional).value())); + } else { + wrapped.push_back(EncodableValue()); + } + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } { auto channel = std::make_unique>( binary_messenger, @@ -2951,6 +3159,44 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, channel->SetMessageHandler(nullptr); } } + { + auto channel = std::make_unique>( + binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "callFlutterEchoEnum", + &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_an_enum_arg = args.at(0); + if (encodable_an_enum_arg.IsNull()) { + reply(WrapError("an_enum_arg unexpectedly null.")); + return; + } + const AnEnum& an_enum_arg = + (AnEnum)encodable_an_enum_arg.LongValue(); + api->CallFlutterEchoEnum( + an_enum_arg, [reply](ErrorOr&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back( + EncodableValue((int)std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } { auto channel = std::make_unique>( binary_messenger, @@ -3234,6 +3480,53 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, channel->SetMessageHandler(nullptr); } } + { + auto channel = std::make_unique>( + binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "callFlutterEchoNullableEnum", + &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_an_enum_arg = args.at(0); + const int64_t an_enum_arg_value = + encodable_an_enum_arg.IsNull() + ? 0 + : encodable_an_enum_arg.LongValue(); + const auto an_enum_arg = + encodable_an_enum_arg.IsNull() + ? std::nullopt + : std::make_optional( + static_cast(an_enum_arg_value)); + api->CallFlutterEchoNullableEnum( + an_enum_arg ? &(*an_enum_arg) : nullptr, + [reply](ErrorOr>&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + auto output_optional = std::move(output).TakeValue(); + if (output_optional) { + wrapped.push_back(EncodableValue( + (int)std::move(output_optional).value())); + } else { + wrapped.push_back(EncodableValue()); + } + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } } EncodableValue HostIntegrationCoreApi::WrapError( @@ -3398,8 +3691,8 @@ void FlutterIntegrationCoreApi::EchoAllTypes( } void FlutterIntegrationCoreApi::EchoAllNullableTypes( - const AllNullableTypes& everything_arg, - std::function&& on_success, + const AllNullableTypes* everything_arg, + std::function&& on_success, std::function&& on_error) { auto channel = std::make_unique>( binary_messenger_, @@ -3407,7 +3700,7 @@ void FlutterIntegrationCoreApi::EchoAllNullableTypes( "echoAllNullableTypes", &GetCodec()); EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ - CustomEncodableValue(everything_arg), + everything_arg ? CustomEncodableValue(*everything_arg) : EncodableValue(), }); channel->Send( encoded_api_arguments, @@ -3416,8 +3709,8 @@ void FlutterIntegrationCoreApi::EchoAllNullableTypes( std::unique_ptr response = GetCodec().DecodeMessage(reply, reply_size); const auto& encodable_return_value = *response; - const auto& return_value = std::any_cast( - std::get(encodable_return_value)); + const auto* return_value = &(std::any_cast( + std::get(encodable_return_value))); on_success(return_value); }); } @@ -3622,6 +3915,29 @@ void FlutterIntegrationCoreApi::EchoMap( }); } +void FlutterIntegrationCoreApi::EchoEnum( + const AnEnum& an_enum_arg, std::function&& on_success, + std::function&& on_error) { + auto channel = std::make_unique>( + binary_messenger_, + "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi." + "echoEnum", + &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue((int)an_enum_arg), + }); + channel->Send( + encoded_api_arguments, + [on_success = std::move(on_success), on_error = std::move(on_error)]( + const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = + GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const AnEnum& return_value = (AnEnum)encodable_return_value.LongValue(); + on_success(return_value); + }); +} + void FlutterIntegrationCoreApi::EchoNullableBool( const bool* a_bool_arg, std::function&& on_success, std::function&& on_error) { @@ -3796,6 +4112,33 @@ void FlutterIntegrationCoreApi::EchoNullableMap( }); } +void FlutterIntegrationCoreApi::EchoNullableEnum( + const AnEnum* an_enum_arg, std::function&& on_success, + std::function&& on_error) { + auto channel = std::make_unique>( + binary_messenger_, + "dev.flutter.pigeon.pigeon_integration_tests.FlutterIntegrationCoreApi." + "echoNullableEnum", + &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + an_enum_arg ? EncodableValue((int)(*an_enum_arg)) : EncodableValue(), + }); + channel->Send(encoded_api_arguments, [on_success = std::move(on_success), + on_error = std::move(on_error)]( + const uint8_t* reply, + size_t reply_size) { + std::unique_ptr response = + GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const int64_t return_value_value = encodable_return_value.IsNull() + ? 0 + : encodable_return_value.LongValue(); + const auto* return_value = + encodable_return_value.IsNull() ? nullptr : &(AnEnum)return_value_value; + on_success(return_value); + }); +} + void FlutterIntegrationCoreApi::NoopAsync( std::function&& on_success, std::function&& on_error) { diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h index 0a7b9f204c8..1076ae465c1 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h +++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h @@ -412,6 +412,8 @@ class HostIntegrationCoreApi { // deserialization. virtual ErrorOr EchoClassWrapper( const AllClassesWrapper& wrapper) = 0; + // Returns the passed enum to test serialization and deserialization. + virtual ErrorOr EchoEnum(const AnEnum& an_enum) = 0; // Returns the passed object, to test serialization and deserialization. virtual ErrorOr> EchoAllNullableTypes( const AllNullableTypes* everything) = 0; @@ -451,6 +453,8 @@ class HostIntegrationCoreApi { // Returns the passed map, to test serialization and deserialization. virtual ErrorOr> EchoNullableMap( const flutter::EncodableMap* a_nullable_map) = 0; + virtual ErrorOr> EchoNullableEnum( + const AnEnum* an_enum) = 0; // A no-op function taking no arguments and returning no value, to sanity // test basic asynchronous calling. virtual void NoopAsync( @@ -476,16 +480,21 @@ class HostIntegrationCoreApi { virtual void EchoAsyncObject( const flutter::EncodableValue& an_object, std::function reply)> result) = 0; - // Returns the passed list, to test serialization and deserialization - // asynchronously. + // Returns the passed list, to test asynchronous serialization and + // deserialization. virtual void EchoAsyncList( const flutter::EncodableList& a_list, std::function reply)> result) = 0; - // Returns the passed map, to test serialization and deserialization - // asynchronously. + // Returns the passed map, to test asynchronous serialization and + // deserialization. virtual void EchoAsyncMap( const flutter::EncodableMap& a_map, std::function reply)> result) = 0; + // Returns the passed enum, to test asynchronous serialization and + // deserialization. + virtual void EchoAsyncEnum( + const AnEnum& an_enum, + std::function reply)> result) = 0; // Responds with an error from an async function returning a value. virtual void ThrowAsyncError( std::function> reply)> @@ -533,18 +542,23 @@ class HostIntegrationCoreApi { const flutter::EncodableValue* an_object, std::function> reply)> result) = 0; - // Returns the passed list, to test serialization and deserialization - // asynchronously. + // Returns the passed list, to test asynchronous serialization and + // deserialization. virtual void EchoAsyncNullableList( const flutter::EncodableList* a_list, std::function> reply)> result) = 0; - // Returns the passed map, to test serialization and deserialization - // asynchronously. + // Returns the passed map, to test asynchronous serialization and + // deserialization. virtual void EchoAsyncNullableMap( const flutter::EncodableMap* a_map, std::function> reply)> result) = 0; + // Returns the passed enum, to test asynchronous serialization and + // deserialization. + virtual void EchoAsyncNullableEnum( + const AnEnum* an_enum, + std::function> reply)> result) = 0; virtual void CallFlutterNoop( std::function reply)> result) = 0; virtual void CallFlutterThrowError( @@ -555,6 +569,10 @@ class HostIntegrationCoreApi { virtual void CallFlutterEchoAllTypes( const AllTypes& everything, std::function reply)> result) = 0; + virtual void CallFlutterEchoAllNullableTypes( + const AllNullableTypes* everything, + std::function> reply)> + result) = 0; virtual void CallFlutterSendMultipleNullableTypes( const bool* a_nullable_bool, const int64_t* a_nullable_int, const std::string* a_nullable_string, @@ -577,6 +595,9 @@ class HostIntegrationCoreApi { virtual void CallFlutterEchoMap( const flutter::EncodableMap& a_map, std::function reply)> result) = 0; + virtual void CallFlutterEchoEnum( + const AnEnum& an_enum, + std::function reply)> result) = 0; virtual void CallFlutterEchoNullableBool( const bool* a_bool, std::function> reply)> result) = 0; @@ -602,6 +623,9 @@ class HostIntegrationCoreApi { const flutter::EncodableMap* a_map, std::function> reply)> result) = 0; + virtual void CallFlutterEchoNullableEnum( + const AnEnum* an_enum, + std::function> reply)> result) = 0; // The codec used by HostIntegrationCoreApi. static const flutter::StandardMessageCodec& GetCodec(); @@ -658,8 +682,8 @@ class FlutterIntegrationCoreApi { std::function&& on_error); // Returns the passed object, to test serialization and deserialization. void EchoAllNullableTypes( - const AllNullableTypes& everything, - std::function&& on_success, + const AllNullableTypes* everything, + std::function&& on_success, std::function&& on_error); // Returns passed in arguments of multiple types. // @@ -695,6 +719,10 @@ class FlutterIntegrationCoreApi { void EchoMap(const flutter::EncodableMap& a_map, std::function&& on_success, std::function&& on_error); + // Returns the passed enum to test serialization and deserialization. + void EchoEnum(const AnEnum& an_enum, + std::function&& on_success, + std::function&& on_error); // Returns the passed boolean, to test serialization and deserialization. void EchoNullableBool(const bool* a_bool, std::function&& on_success, @@ -726,6 +754,10 @@ class FlutterIntegrationCoreApi { const flutter::EncodableMap* a_map, std::function&& on_success, std::function&& on_error); + // Returns the passed enum to test serialization and deserialization. + void EchoNullableEnum(const AnEnum* an_enum, + std::function&& on_success, + std::function&& on_error); // A no-op function taking no arguments and returning no value, to sanity // test basic asynchronous calling. void NoopAsync(std::function&& on_success, diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp index 125771085ce..ea71a076344 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp @@ -19,6 +19,7 @@ namespace test_plugin { using core_tests_pigeontest::AllClassesWrapper; using core_tests_pigeontest::AllNullableTypes; using core_tests_pigeontest::AllTypes; +using core_tests_pigeontest::AnEnum; using core_tests_pigeontest::ErrorOr; using core_tests_pigeontest::FlutterError; using core_tests_pigeontest::FlutterIntegrationCoreApi; @@ -103,6 +104,8 @@ ErrorOr TestPlugin::EchoClassWrapper( return wrapper; } +ErrorOr TestPlugin::EchoEnum(const AnEnum& an_enum) { return an_enum; } + ErrorOr> TestPlugin::ExtractNestedNullableString( const AllClassesWrapper& wrapper) { const std::string* inner_string = @@ -207,6 +210,14 @@ ErrorOr> TestPlugin::EchoNullableMap( return *a_nullable_map; }; +ErrorOr> TestPlugin::EchoNullableEnum( + const AnEnum* an_enum) { + if (!an_enum) { + return std::nullopt; + } + return *an_enum; +} + void TestPlugin::NoopAsync( std::function reply)> result) { result(std::nullopt); @@ -277,6 +288,11 @@ void TestPlugin::EchoAsyncMap( result(a_map); } +void TestPlugin::EchoAsyncEnum( + const AnEnum& an_enum, std::function reply)> result) { + result(an_enum); +} + void TestPlugin::EchoAsyncNullableAllNullableTypes( const AllNullableTypes* everything, std::function> reply)> @@ -335,6 +351,12 @@ void TestPlugin::EchoAsyncNullableMap( result(a_map ? std::optional(*a_map) : std::nullopt); } +void TestPlugin::EchoAsyncNullableEnum( + const AnEnum* an_enum, + std::function> reply)> result) { + result(an_enum ? std::optional(*an_enum) : std::nullopt); +} + void TestPlugin::CallFlutterNoop( std::function reply)> result) { flutter_api_->Noop([result]() { result(std::nullopt); }, @@ -366,6 +388,18 @@ void TestPlugin::CallFlutterEchoAllTypes( [result](const FlutterError& error) { result(error); }); } +void TestPlugin::CallFlutterEchoAllNullableTypes( + const AllNullableTypes* everything, + std::function> reply)> + result) { + flutter_api_->EchoAllNullableTypes( + everything, + [result](const AllNullableTypes* echo) { + result(echo ? std::optional(*echo) : std::nullopt); + }, + [result](const FlutterError& error) { result(error); }); +} + void TestPlugin::CallFlutterSendMultipleNullableTypes( const bool* a_nullable_bool, const int64_t* a_nullable_int, const std::string* a_nullable_string, @@ -429,6 +463,13 @@ void TestPlugin::CallFlutterEchoMap( [result](const FlutterError& error) { result(error); }); } +void TestPlugin::CallFlutterEchoEnum( + const AnEnum& an_enum, std::function reply)> result) { + flutter_api_->EchoEnum( + an_enum, [result](const AnEnum& echo) { result(echo); }, + [result](const FlutterError& error) { result(error); }); +} + void TestPlugin::CallFlutterEchoNullableBool( const bool* a_bool, std::function> reply)> result) { @@ -508,4 +549,15 @@ void TestPlugin::CallFlutterEchoNullableMap( [result](const FlutterError& error) { result(error); }); } +void TestPlugin::CallFlutterEchoNullableEnum( + const AnEnum* an_enum, + std::function> reply)> result) { + flutter_api_->EchoNullableEnum( + an_enum, + [result](const AnEnum* echo) { + result(echo ? std::optional(*echo) : std::nullopt); + }, + [result](const FlutterError& error) { result(error); }); +} + } // namespace test_plugin diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h index 649d20fab5d..d66a8e5836a 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h +++ b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h @@ -61,6 +61,8 @@ class TestPlugin : public flutter::Plugin, core_tests_pigeontest::ErrorOr EchoClassWrapper( const core_tests_pigeontest::AllClassesWrapper& wrapper) override; + core_tests_pigeontest::ErrorOr EchoEnum( + const core_tests_pigeontest::AnEnum& an_enum) override; core_tests_pigeontest::ErrorOr> ExtractNestedNullableString( const core_tests_pigeontest::AllClassesWrapper& wrapper) override; @@ -87,6 +89,8 @@ class TestPlugin : public flutter::Plugin, EchoNullableList(const flutter::EncodableList* a_nullable_list) override; core_tests_pigeontest::ErrorOr> EchoNullableMap(const flutter::EncodableMap* a_nullable_map) override; + core_tests_pigeontest::ErrorOr> + EchoNullableEnum(const core_tests_pigeontest::AnEnum* an_enum) override; void NoopAsync(std::function< void(std::optional reply)> result) override; @@ -152,6 +156,11 @@ class TestPlugin : public flutter::Plugin, std::function< void(core_tests_pigeontest::ErrorOr reply)> result) override; + void EchoAsyncEnum( + const core_tests_pigeontest::AnEnum& an_enum, + std::function reply)> + result) override; void EchoAsyncNullableInt( const int64_t* an_int, std::function< @@ -196,6 +205,12 @@ class TestPlugin : public flutter::Plugin, core_tests_pigeontest::ErrorOr> reply)> result) override; + void EchoAsyncNullableEnum( + const core_tests_pigeontest::AnEnum* an_enum, + std::function> + reply)> + result) override; void CallFlutterNoop( std::function< void(std::optional reply)> @@ -215,6 +230,12 @@ class TestPlugin : public flutter::Plugin, void(core_tests_pigeontest::ErrorOr reply)> result) override; + void CallFlutterEchoAllNullableTypes( + const core_tests_pigeontest::AllNullableTypes* everything, + std::function> + reply)> + result) override; void CallFlutterSendMultipleNullableTypes( const bool* a_nullable_bool, const int64_t* a_nullable_int, const std::string* a_nullable_string, @@ -253,6 +274,11 @@ class TestPlugin : public flutter::Plugin, std::function< void(core_tests_pigeontest::ErrorOr reply)> result) override; + void CallFlutterEchoEnum( + const core_tests_pigeontest::AnEnum& an_enum, + std::function reply)> + result) override; void CallFlutterEchoNullableBool( const bool* a_bool, std::function< @@ -291,6 +317,12 @@ class TestPlugin : public flutter::Plugin, core_tests_pigeontest::ErrorOr> reply)> result) override; + void CallFlutterEchoNullableEnum( + const core_tests_pigeontest::AnEnum* an_enum, + std::function> + reply)> + result) override; private: std::unique_ptr diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index 68516fcfa6d..3c7a70e8ff5 100644 --- a/packages/pigeon/pubspec.yaml +++ b/packages/pigeon/pubspec.yaml @@ -2,7 +2,7 @@ name: pigeon description: Code generator tool to make communication between Flutter and the host platform type-safe and easier. repository: https://github.com/flutter/packages/tree/main/packages/pigeon issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3Apigeon -version: 10.1.6 # This must match the version in lib/generator_tools.dart +version: 11.0.0 # This must match the version in lib/generator_tools.dart environment: sdk: ">=2.19.0 <4.0.0" diff --git a/packages/pigeon/test/dart_generator_test.dart b/packages/pigeon/test/dart_generator_test.dart index be31794a744..d74bdc383d0 100644 --- a/packages/pigeon/test/dart_generator_test.dart +++ b/packages/pigeon/test/dart_generator_test.dart @@ -1611,6 +1611,6 @@ name: foobar expect( testCode, contains( - 'final Enum? arg_anEnum = args[0] == null ? null : Enum.values[args[0] as int]')); + 'final Enum? arg_anEnum = args[0] == null ? null : Enum.values[args[0]! as int]')); }); } diff --git a/packages/pigeon/test/objc_generator_test.dart b/packages/pigeon/test/objc_generator_test.dart index 3d30cc9ba57..d6c1f5cfa48 100644 --- a/packages/pigeon/test/objc_generator_test.dart +++ b/packages/pigeon/test/objc_generator_test.dart @@ -168,7 +168,7 @@ void main() { expect( code, contains( - 'pigeonResult.enum1 = [GetNullableObjectAtIndex(list, 1) integerValue];')); + 'Enum1Box *enum1 = enum1AsNumber == nil ? nil : [[Enum1Box alloc] initWithValue: [enum1AsNumber integerValue]];')); }); test('primitive enum host', () { @@ -298,7 +298,8 @@ void main() { dartPackageName: DEFAULT_PACKAGE_NAME, ); final String code = sink.toString(); - expect(code, contains('@property(nonatomic, assign) Enum1 enum1')); + expect(code, + contains('@property(nonatomic, strong, nullable) Enum1Box * enum1;')); }); test('gen one api header', () { diff --git a/packages/pigeon/test/pigeon_lib_test.dart b/packages/pigeon/test/pigeon_lib_test.dart index 7e7cc216d8c..bf6e0ba33f5 100644 --- a/packages/pigeon/test/pigeon_lib_test.dart +++ b/packages/pigeon/test/pigeon_lib_test.dart @@ -765,7 +765,6 @@ abstract class Api { }); test('enums argument flutter', () { - // TODO(gaaclarke): Make this not an error: https://github.com/flutter/flutter/issues/87307 const String code = ''' enum Foo { @@ -779,12 +778,10 @@ abstract class Api { } '''; final ParseResults parseResult = parseSource(code); - expect(parseResult.errors.length, equals(1)); - expect(parseResult.errors[0].message, contains('Enums')); + expect(parseResult.errors.length, equals(0)); }); test('enums list argument', () { - // TODO(tarrinneal): Make this not an error: https://github.com/flutter/flutter/issues/87307 const String code = ''' enum Foo { one, two } @@ -794,12 +791,10 @@ abstract class Api { } '''; final ParseResults parseResult = parseSource(code); - expect(parseResult.errors.length, equals(1)); - expect(parseResult.errors[0].message, contains('Enums')); + expect(parseResult.errors.length, equals(0)); }); test('enums map argument key', () { - // TODO(tarrinneal): Make this not an error: https://github.com/flutter/flutter/issues/87307 const String code = ''' enum Foo { one, two } @@ -809,12 +804,10 @@ abstract class Api { } '''; final ParseResults parseResult = parseSource(code); - expect(parseResult.errors.length, equals(1)); - expect(parseResult.errors[0].message, contains('Enums')); + expect(parseResult.errors.length, equals(0)); }); test('enums map argument value', () { - // TODO(tarrinneal): Make this not an error: https://github.com/flutter/flutter/issues/87307 const String code = ''' enum Foo { one, two } @@ -824,12 +817,10 @@ abstract class Api { } '''; final ParseResults parseResult = parseSource(code); - expect(parseResult.errors.length, equals(1)); - expect(parseResult.errors[0].message, contains('Enums')); + expect(parseResult.errors.length, equals(0)); }); test('enums return value', () { - // TODO(gaaclarke): Make this not an error: https://github.com/flutter/flutter/issues/87307 const String code = ''' enum Foo { @@ -843,8 +834,7 @@ abstract class Api { } '''; final ParseResults parseResult = parseSource(code); - expect(parseResult.errors.length, equals(1)); - expect(parseResult.errors[0].message, contains('Enums')); + expect(parseResult.errors.length, equals(0)); }); test('return type generics', () { diff --git a/packages/pigeon/test/swift_generator_test.dart b/packages/pigeon/test/swift_generator_test.dart index 2870f5788e4..cd46023b5dc 100644 --- a/packages/pigeon/test/swift_generator_test.dart +++ b/packages/pigeon/test/swift_generator_test.dart @@ -1069,7 +1069,7 @@ void main() { expect( code, contains( - 'let fooArg: Int64? = args[0] is NSNull ? nil : (args[0] is Int64? ? args[0] as! Int64? : Int64(args[0] as! Int32))')); + 'let fooArg: Int64? = isNullish(args[0]) ? nil : (args[0] is Int64? ? args[0] as! Int64? : Int64(args[0] as! Int32))')); }); test('nullable argument flutter', () { diff --git a/packages/pigeon/tool/shared/generation.dart b/packages/pigeon/tool/shared/generation.dart index 3b037304c65..de03c3c9424 100644 --- a/packages/pigeon/tool/shared/generation.dart +++ b/packages/pigeon/tool/shared/generation.dart @@ -245,7 +245,6 @@ Future formatAllFiles({required String repositoryRoot}) { 'format', '--packages=pigeon', ], - streamOutput: false, workingDirectory: repositoryRoot, logFailure: true); } diff --git a/packages/pigeon/tool/shared/test_runner.dart b/packages/pigeon/tool/shared/test_runner.dart index 38935cf6913..c2df4b58f06 100644 --- a/packages/pigeon/tool/shared/test_runner.dart +++ b/packages/pigeon/tool/shared/test_runner.dart @@ -15,13 +15,14 @@ import 'test_suites.dart'; /// them fails. Future runTests( List testsToRun, { + bool runFormat = false, bool runGeneration = true, }) async { + final String baseDir = p.dirname(p.dirname(Platform.script.toFilePath())); if (runGeneration) { // Pre-generate the necessary common output files. // TODO(stuartmorgan): Consider making this conditional on the specific // tests being run, as not all of them need these files. - final String baseDir = p.dirname(p.dirname(Platform.script.toFilePath())); print('# Generating platform_test/ output...'); final int generateExitCode = await generateTestPigeons(baseDir: baseDir); if (generateExitCode == 0) { @@ -31,6 +32,16 @@ Future runTests( } } + if (runFormat) { + print('Formatting generated output...'); + final int formatExitCode = + await formatAllFiles(repositoryRoot: p.dirname(p.dirname(baseDir))); + if (formatExitCode != 0) { + print('Formatting failed; see above for errors.'); + exit(formatExitCode); + } + } + for (final String test in testsToRun) { final TestInfo? info = testSuites[test]; if (info != null) { diff --git a/packages/pigeon/tool/test.dart b/packages/pigeon/tool/test.dart index 8d7e71b1c5d..83c09684c05 100644 --- a/packages/pigeon/tool/test.dart +++ b/packages/pigeon/tool/test.dart @@ -20,12 +20,15 @@ import 'shared/test_suites.dart'; const String _testFlag = 'test'; const String _noGen = 'no-generation'; const String _listFlag = 'list'; +const String _format = 'format'; Future main(List args) async { final ArgParser parser = ArgParser() ..addMultiOption(_testFlag, abbr: 't', help: 'Only run specified tests.') ..addFlag(_noGen, abbr: 'g', help: 'Skips the generation step.', negatable: false) + ..addFlag(_format, + abbr: 'f', help: 'Formats generated test files before running tests.') ..addFlag(_listFlag, negatable: false, abbr: 'l', help: 'List available tests.') ..addFlag('help', @@ -108,5 +111,9 @@ ${parser.usage}'''); } } - await runTests(testsToRun, runGeneration: !argResults.wasParsed(_noGen)); + await runTests( + testsToRun, + runGeneration: !argResults.wasParsed(_noGen), + runFormat: argResults.wasParsed(_format), + ); }