Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/pigeon/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* [front-end] Added a more explicit error for static fields.
* [front-end] Added more errors for incorrect usage of Pigeon (previously they were just ignored).
* Moved Pigeon to using a custom codec which allows collection types to contain custom classes.
* Started allowing primitive data types as arguments and return types.

## 0.3.0

Expand Down
13 changes: 4 additions & 9 deletions packages/pigeon/lib/dart_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,14 @@ final BinaryMessenger$nullTag _binaryMessenger;
}
String argSignature = '';
String sendArgument = 'null';
String? encodedDeclaration;
if (func.argType != 'void') {
argSignature = '${func.argType} arg';
sendArgument = 'encoded';
encodedDeclaration = 'final Object encoded = arg.encode();';
sendArgument = 'arg';
}
indent.write(
'Future<${func.returnType}> ${func.name}($argSignature) async ',
);
indent.scoped('{', '}', () {
if (encodedDeclaration != null) {
indent.writeln(encodedDeclaration);
}
final String channelName = makeChannelName(api, func);
indent.writeln(
'final BasicMessageChannel<Object$nullTag> channel = BasicMessageChannel<Object$nullTag>(');
Expand All @@ -144,7 +139,7 @@ final BinaryMessenger$nullTag _binaryMessenger;
});
final String returnStatement = func.returnType == 'void'
? '// noop'
: 'return ${func.returnType}.decode(replyMap[\'${Keys.result}\']$unwrapOperator);';
: 'return (replyMap[\'${Keys.result}\'] as ${func.returnType}$nullTag)$unwrapOperator;';
indent.format('''
final Map<Object$nullTag, Object$nullTag>$nullTag replyMap =\n\t\tawait channel.send($sendArgument) as Map<Object$nullTag, Object$nullTag>$nullTag;
if (replyMap == null) {
Expand Down Expand Up @@ -237,7 +232,7 @@ void _writeFlutterApi(
'assert(message != null, \'Argument for $channelName was null. Expected $argType.\');',
);
indent.writeln(
'final $argType input = $argType.decode(message$unwrapOperator);',
'final $argType input = (message as $argType$nullTag)$unwrapOperator;',
);
call = 'api.${func.name}(input)';
}
Expand All @@ -254,7 +249,7 @@ void _writeFlutterApi(
} else {
indent.writeln('final $returnType output = $call;');
}
const String returnExpression = 'output.encode()';
const String returnExpression = 'output';
final String returnStatement = isMockHandler
? 'return <Object$nullTag, Object$nullTag>{\'${Keys.result}\': $returnExpression};'
: 'return $returnExpression;';
Expand Down
20 changes: 18 additions & 2 deletions packages/pigeon/lib/generator_tools.dart
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,20 @@ class EnumeratedClass {
final int enumeration;
}

/// Supported basic datatypes.
const List<String> validTypes = <String>[
'String',
'bool',
'int',
'double',
'Uint8List',
'Int32List',
'Int64List',
'Float64List',
'List',
'Map',
];

/// Custom codecs' custom types are enumerated from 255 down to this number to
/// avoid collisions with the StandardMessageCodec.
const int _minimumCodecFieldKey = 128;
Expand All @@ -274,8 +288,10 @@ Iterable<EnumeratedClass> getCodecClasses(Api api) sync* {
names.add(method.returnType);
names.add(method.argType);
}
final List<String> sortedNames =
names.where((String element) => element != 'void').toList();
final List<String> sortedNames = names
.where((String element) =>
element != 'void' && !validTypes.contains(element))
.toList();
sortedNames.sort();
int enumeration = _minimumCodecFieldKey;
const int maxCustomClassesPerApi = 255 - _minimumCodecFieldKey;
Expand Down
60 changes: 40 additions & 20 deletions packages/pigeon/lib/java_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,22 @@ void _writeCodec(Indent indent, Api api) {
});
}

/// This performs Dart to Java type conversions. If performs a passthrough of
/// the input if it can't be converted.
// TODO(gaaclarke): Remove this method and unify it with `_javaTypeForDartType`.
String _javaTypeForDartTypePassthrough(String type) {
const Map<String, String> map = <String, String>{
'int': 'Integer',
'bool': 'Boolean',
'double': 'Double',
'Int32List': 'int[]',
'Uint8List': 'byte[]',
'Int64List': 'long[]',
'Float64List': 'double[]',
};
return map[type] ?? type;
}

void _writeHostApi(Indent indent, Api api) {
assert(api.location == ApiLocation.host);

Expand All @@ -121,11 +137,13 @@ void _writeHostApi(Indent indent, Api api) {
indent.write('public interface ${api.name} ');
indent.scoped('{', '}', () {
for (final Method method in api.methods) {
final String returnType =
method.isAsynchronous ? 'void' : method.returnType;
final String argType = _javaTypeForDartTypePassthrough(method.argType);
final String returnType = method.isAsynchronous
? 'void'
: _javaTypeForDartTypePassthrough(method.returnType);
final List<String> argSignature = <String>[];
if (method.argType != 'void') {
argSignature.add('${method.argType} arg');
argSignature.add('$argType arg');
}
if (method.isAsynchronous) {
final String returnType =
Expand Down Expand Up @@ -162,21 +180,27 @@ static MessageCodec<Object> getCodec() {
indent.scoped('{', '} else {', () {
indent.write('channel.setMessageHandler((message, reply) -> ');
indent.scoped('{', '});', () {
final String argType = method.argType;
final String returnType = method.returnType;
final String argType =
_javaTypeForDartTypePassthrough(method.argType);
final String returnType =
_javaTypeForDartTypePassthrough(method.returnType);
indent.writeln('Map<String, Object> wrapped = new HashMap<>();');
indent.write('try ');
indent.scoped('{', '}', () {
final List<String> methodArgument = <String>[];
if (argType != 'void') {
indent.writeln('@SuppressWarnings("ConstantConditions")');
indent.writeln(
'$argType input = $argType.fromMap((Map<String, Object>)message);');
indent.writeln('$argType input = ($argType)message;');
Comment thread
stuartmorgan-g marked this conversation as resolved.
indent.write('if (input == null) ');
indent.scoped('{', '}', () {
indent.writeln(
'throw new NullPointerException("Message unexpectedly null.");');
});
methodArgument.add('input');
}
if (method.isAsynchronous) {
final String resultValue =
method.returnType == 'void' ? 'null' : 'result.toMap()';
method.returnType == 'void' ? 'null' : 'result';
methodArgument.add(
'result -> { '
'wrapped.put("${Keys.result}", $resultValue); '
Expand All @@ -193,8 +217,7 @@ static MessageCodec<Object> getCodec() {
indent.writeln('wrapped.put("${Keys.result}", null);');
} else {
indent.writeln('$returnType output = $call;');
indent.writeln(
'wrapped.put("${Keys.result}", output.toMap());');
indent.writeln('wrapped.put("${Keys.result}", output);');
}
});
indent.write('catch (Error | RuntimeException exception) ');
Expand Down Expand Up @@ -242,16 +265,18 @@ static MessageCodec<Object> getCodec() {
''');
for (final Method func in api.methods) {
final String channelName = makeChannelName(api, func);
final String returnType =
func.returnType == 'void' ? 'Void' : func.returnType;
final String returnType = func.returnType == 'void'
? 'Void'
: _javaTypeForDartTypePassthrough(func.returnType);
final String argType = _javaTypeForDartTypePassthrough(func.argType);
String sendArgument;
if (func.argType == 'void') {
indent.write('public void ${func.name}(Reply<$returnType> callback) ');
sendArgument = 'null';
} else {
indent.write(
'public void ${func.name}(${func.argType} argInput, Reply<$returnType> callback) ');
sendArgument = 'inputMap';
'public void ${func.name}($argType argInput, Reply<$returnType> callback) ');
sendArgument = 'argInput';
}
indent.scoped('{', '}', () {
indent.writeln('BasicMessageChannel<Object> channel =');
Expand All @@ -261,18 +286,13 @@ static MessageCodec<Object> getCodec() {
'new BasicMessageChannel<>(binaryMessenger, "$channelName", getCodec());');
indent.dec();
indent.dec();
if (func.argType != 'void') {
indent.writeln('Map<String, Object> inputMap = argInput.toMap();');
}
indent.write('channel.send($sendArgument, channelReply -> ');
indent.scoped('{', '});', () {
if (func.returnType == 'void') {
indent.writeln('callback.reply(null);');
} else {
indent.writeln('Map outputMap = (Map)channelReply;');
indent.writeln('@SuppressWarnings("ConstantConditions")');
indent.writeln(
'${func.returnType} output = ${func.returnType}.fromMap(outputMap);');
indent.writeln('$returnType output = ($returnType)channelReply;');
indent.writeln('callback.reply(output);');
}
});
Expand Down
Loading