Visitar URL original
[Pigeon] added support for void return types (#121) · flutter/packages@d410ceb · GitHub
Skip to content

Commit d410ceb

Browse files
authored
[Pigeon] added support for void return types (#121)
1 parent 5cbb850 commit d410ceb

13 files changed

Lines changed: 264 additions & 26 deletions

‎packages/pigeon/CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.1.0-experimental.6
2+
3+
* Added support for void return types.
4+
15
## 0.1.0-experimental.5
26

37
* Fixed runtime exception in Android with values of ints less than 2^32.

‎packages/pigeon/lib/dart_generator.dart‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ void _writeHostApi(Indent indent, Api api) {
2323
indent.dec();
2424
indent.dec();
2525
indent.writeln('');
26+
final String returnStatement =
27+
func.returnType == 'void'
28+
? '// noop'
29+
: 'return ${func.returnType}._fromMap(replyMap[\'${Keys.result}\']);';
2630
indent.format('''Map replyMap = await channel.send(requestMap);
2731
if (replyMap['error'] != null) {
2832
\tMap error = replyMap['${Keys.error}'];
@@ -31,7 +35,7 @@ if (replyMap['error'] != null) {
3135
\t\t\tmessage: error['${Keys.errorMessage}'],
3236
\t\t\tdetails: error['${Keys.errorDetails}']);
3337
} else {
34-
\treturn ${func.returnType}._fromMap(replyMap[\'${Keys.result}\']);
38+
\t$returnStatement
3539
}
3640
''');
3741
});
@@ -67,8 +71,13 @@ void _writeFlutterApi(Indent indent, Api api) {
6771
final String returnType = func.returnType;
6872
indent.writeln('Map mapMessage = message as Map;');
6973
indent.writeln('$argType input = $argType._fromMap(mapMessage);');
70-
indent.writeln('$returnType output = api.${func.name}(input);');
71-
indent.writeln('return output._toMap();');
74+
final String call = 'api.${func.name}(input)';
75+
if (returnType == 'void') {
76+
indent.writeln('$call;');
77+
} else {
78+
indent.writeln('$returnType output = $call;');
79+
indent.writeln('return output._toMap();');
80+
}
7281
});
7382
});
7483
}

‎packages/pigeon/lib/generator_tools.dart‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44

55
import 'dart:convert';
66
import 'dart:io';
7+
import 'dart:mirrors';
78
import 'ast.dart';
89

910
/// The current version of pigeon.
10-
const String pigeonVersion = '0.1.0-experimental.5';
11+
const String pigeonVersion = '0.1.0-experimental.6';
1112

1213
/// Read all the content from [stdin] to a String.
1314
String readStdin() {
@@ -154,3 +155,8 @@ class Keys {
154155
/// The key in an error hash for the 'details' value.
155156
static const String errorDetails = 'details';
156157
}
158+
159+
/// Returns true if `type` represents 'void'.
160+
bool isVoid(TypeMirror type) {
161+
return MirrorSystem.getName(type.simpleName) == 'void';
162+
}

‎packages/pigeon/lib/java_generator.dart‎

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,15 @@ void _writeHostApi(Indent indent, Api api) {
6666
'HashMap<String, HashMap> wrapped = new HashMap<String, HashMap>();');
6767
indent.write('try ');
6868
indent.scoped('{', '}', () {
69-
indent
70-
.writeln('$returnType output = api.${method.name}(input);');
71-
indent
72-
.writeln('wrapped.put("${Keys.result}", output.toMap());');
69+
final String call = 'api.${method.name}(input)';
70+
if (method.returnType == 'void') {
71+
indent.writeln('$call;');
72+
indent.writeln('wrapped.put("${Keys.result}", null);');
73+
} else {
74+
indent.writeln('$returnType output = $call;');
75+
indent.writeln(
76+
'wrapped.put("${Keys.result}", output.toMap());');
77+
}
7378
});
7479
indent.write('catch (Exception exception) ');
7580
indent.scoped('{', '}', () {
@@ -102,8 +107,10 @@ void _writeFlutterApi(Indent indent, Api api) {
102107
});
103108
for (Method func in api.methods) {
104109
final String channelName = makeChannelName(api, func);
110+
final String returnType =
111+
func.returnType == 'void' ? 'Void' : func.returnType;
105112
indent.write(
106-
'public void ${func.name}(${func.argType} argInput, Reply<${func.returnType}> callback) ');
113+
'public void ${func.name}(${func.argType} argInput, Reply<$returnType> callback) ');
107114
indent.scoped('{', '}', () {
108115
indent.writeln('BasicMessageChannel<Object> channel =');
109116
indent.inc();
@@ -118,10 +125,14 @@ void _writeFlutterApi(Indent indent, Api api) {
118125
indent.scoped('{', '});', () {
119126
indent.write('public void reply(Object channelReply) ');
120127
indent.scoped('{', '}', () {
121-
indent.writeln('HashMap outputMap = (HashMap)channelReply;');
122-
indent.writeln(
123-
'${func.returnType} output = ${func.returnType}.fromMap(outputMap);');
124-
indent.writeln('callback.reply(output);');
128+
if (func.returnType == 'void') {
129+
indent.writeln('callback.reply(null);');
130+
} else {
131+
indent.writeln('HashMap outputMap = (HashMap)channelReply;');
132+
indent.writeln(
133+
'${func.returnType} output = ${func.returnType}.fromMap(outputMap);');
134+
indent.writeln('callback.reply(output);');
135+
}
125136
});
126137
});
127138
});

‎packages/pigeon/lib/objc_generator.dart‎

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ String _className(String prefix, String className) {
2626
}
2727
}
2828

29+
String _callbackForType(String dartType, String objcType) {
30+
return dartType == 'void'
31+
? 'void(^)(NSError*)'
32+
: 'void(^)($objcType*, NSError*)';
33+
}
34+
2935
const Map<String, String> _objcTypeForDartTypeMap = <String, String>{
3036
'bool': 'NSNumber *',
3137
'int': 'NSNumber *',
@@ -101,10 +107,13 @@ void generateObjcHeader(ObjcOptions options, Root root, StringSink sink) {
101107
if (api.location == ApiLocation.host) {
102108
indent.writeln('@protocol $apiName');
103109
for (Method func in api.methods) {
104-
final String returnType = _className(options.prefix, func.returnType);
110+
final String returnTypeName =
111+
_className(options.prefix, func.returnType);
105112
final String argType = _className(options.prefix, func.argType);
113+
final String returnType =
114+
func.returnType == 'void' ? 'void' : '$returnTypeName *';
106115
indent.writeln(
107-
'-($returnType *)${func.name}:($argType*)input error:(FlutterError **)error;');
116+
'-($returnType)${func.name}:($argType*)input error:(FlutterError **)error;');
108117
}
109118
indent.writeln('@end');
110119
indent.writeln('');
@@ -118,8 +127,9 @@ void generateObjcHeader(ObjcOptions options, Root root, StringSink sink) {
118127
for (Method func in api.methods) {
119128
final String returnType = _className(options.prefix, func.returnType);
120129
final String argType = _className(options.prefix, func.argType);
130+
final String callbackType = _callbackForType(func.returnType, returnType);
121131
indent.writeln(
122-
'- (void)${func.name}:($argType*)input completion:(void(^)($returnType*, NSError*))completion;');
132+
'- (void)${func.name}:($argType*)input completion:($callbackType)completion;');
123133
}
124134
indent.writeln('@end');
125135
}
@@ -176,9 +186,14 @@ void _writeHostApiSource(Indent indent, ObjcOptions options, Api api) {
176186
_className(options.prefix, func.returnType);
177187
indent.writeln('$argType *input = [$argType fromMap:message];');
178188
indent.writeln('FlutterError *error;');
179-
indent.writeln(
180-
'$returnType *output = [api ${func.name}:input error:&error];');
181-
indent.writeln('callback(wrapResult([output toMap], error));');
189+
final String call = '[api ${func.name}:input error:&error]';
190+
if (func.returnType == 'void') {
191+
indent.writeln('$call;');
192+
indent.writeln('callback(wrapResult(nil, error));');
193+
} else {
194+
indent.writeln('$returnType *output = $call;');
195+
indent.writeln('callback(wrapResult([output toMap], error));');
196+
}
182197
});
183198
});
184199
indent.write('else ');
@@ -213,8 +228,10 @@ void _writeFlutterApiSource(Indent indent, ObjcOptions options, Api api) {
213228
for (Method func in api.methods) {
214229
final String returnType = _className(options.prefix, func.returnType);
215230
final String argType = _className(options.prefix, func.argType);
231+
final String callbackType = _callbackForType(func.returnType, returnType);
232+
216233
indent.write(
217-
'- (void)${func.name}:($argType*)input completion:(void(^)($returnType*, NSError*))completion ');
234+
'- (void)${func.name}:($argType*)input completion:($callbackType)completion ');
218235
indent.scoped('{', '}', () {
219236
indent.writeln('FlutterBasicMessageChannel *channel =');
220237
indent.inc();
@@ -227,10 +244,14 @@ void _writeFlutterApiSource(Indent indent, ObjcOptions options, Api api) {
227244
indent.writeln('NSDictionary* inputMap = [input toMap];');
228245
indent.write('[channel sendMessage:inputMap reply:^(id reply) ');
229246
indent.scoped('{', '}];', () {
230-
indent.writeln('NSDictionary* outputMap = reply;');
231-
indent
232-
.writeln('$returnType * output = [$returnType fromMap:outputMap];');
233-
indent.writeln('completion(output, nil);');
247+
if (func.returnType == 'void') {
248+
indent.writeln('completion(nil);');
249+
} else {
250+
indent.writeln('NSDictionary* outputMap = reply;');
251+
indent.writeln(
252+
'$returnType * output = [$returnType fromMap:outputMap];');
253+
indent.writeln('completion(output, nil);');
254+
}
234255
});
235256
});
236257
}

‎packages/pigeon/lib/pigeon_lib.dart‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:pigeon/java_generator.dart';
1111

1212
import 'ast.dart';
1313
import 'dart_generator.dart';
14+
import 'generator_tools.dart';
1415
import 'objc_generator.dart';
1516

1617
const List<String> _validTypes = <String>[
@@ -152,7 +153,9 @@ class Pigeon {
152153
for (ClassMirror apiMirror in apis) {
153154
for (DeclarationMirror declaration in apiMirror.declarations.values) {
154155
if (declaration is MethodMirror && !declaration.isConstructor) {
155-
classes.add(declaration.returnType);
156+
if (!isVoid(declaration.returnType)) {
157+
classes.add(declaration.returnType);
158+
}
156159
classes.add(declaration.parameters[0].type);
157160
}
158161
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2020 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:pigeon/pigeon_lib.dart';
6+
7+
class SetRequest {
8+
int value;
9+
}
10+
11+
@FlutterApi()
12+
abstract class Api {
13+
void setValue(SetRequest request);
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2020 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:pigeon/pigeon_lib.dart';
6+
7+
class SetRequest {
8+
int value;
9+
}
10+
11+
@HostApi()
12+
abstract class Api {
13+
void setValue(SetRequest request);
14+
}

‎packages/pigeon/pubspec.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: pigeon
2-
version: 0.1.0-experimental.5
2+
version: 0.1.0-experimental.6
33
description: Code generator tool to make communication between Flutter and the host platform type-safe and easier.
44
homepage: https://github.com/flutter/packages/tree/master/packages/pigeon
55
dependencies:

‎packages/pigeon/test/dart_generator_test.dart‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,39 @@ void main() {
8181
expect(code, contains('abstract class Api'));
8282
expect(code, contains('void ApiSetup(Api'));
8383
});
84+
85+
test('host void', () {
86+
final Root root = Root(apis: <Api>[
87+
Api(name: 'Api', location: ApiLocation.host, methods: <Method>[
88+
Method(name: 'doSomething', argType: 'Input', returnType: 'void')
89+
])
90+
], classes: <Class>[
91+
Class(
92+
name: 'Input',
93+
fields: <Field>[Field(name: 'input', dataType: 'String')]),
94+
]);
95+
final StringBuffer sink = StringBuffer();
96+
generateDart(root, sink);
97+
final String code = sink.toString();
98+
expect(code, contains('Future<void> doSomething'));
99+
expect(code, contains('// noop'));
100+
});
101+
102+
test('flutter void', () {
103+
final Root root = Root(apis: <Api>[
104+
Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[
105+
Method(name: 'doSomething', argType: 'Input', returnType: 'void')
106+
])
107+
], classes: <Class>[
108+
Class(
109+
name: 'Input',
110+
fields: <Field>[Field(name: 'input', dataType: 'String')]),
111+
]);
112+
final StringBuffer sink = StringBuffer();
113+
generateDart(root, sink);
114+
final String code = sink.toString();
115+
expect(code, isNot(matches('=.*doSomething')));
116+
expect(code, contains('doSomething('));
117+
expect(code, isNot(contains('._toMap()')));
118+
});
84119
}

0 commit comments

Comments
 (0)