Skip to content

Commit

Permalink
[Pigeon]: version 0.1.0 (objc and testing features) (flutter#152)
Browse files Browse the repository at this point in the history
  • Loading branch information
gaaclarke authored May 27, 2020
1 parent 5f3e639 commit 18b52ae
Show file tree
Hide file tree
Showing 33 changed files with 485 additions and 89 deletions.
6 changes: 6 additions & 0 deletions packages/pigeon/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.1.0

* Added pigeon.dart.
* Fixed some Obj-C linter problems.
* Added the ability to generate a mock handler in Dart.

## 0.1.0-experimental.11

* Fixed setting an api to null in Java.
Expand Down
4 changes: 2 additions & 2 deletions packages/pigeon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ doesn't need to worry about conflicting versions of Pigeon.

### Rules for defining your communication interface

1) The file should contain no methods or function definitions.
1) The file should contain no method or function definitions.
1) Datatypes are defined as classes with fields of the supported datatypes (see
the supported Datatypes section).
1) Api's should be defined as an `abstract class` with either `HostApi()` or
`FlutterApi()` as metadata. The former being for procedures that are defined
on the host platform and the latter for procedures that are defined in Dart.
1) Method declarations on the Api classes should have one argument and a return
value whose types are defined in the file.
value whose types are defined in the file or be `void`.

## Example

Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
arguments=
auto.sync=false
build.scans.enabled=false
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
connection.project.dir=
eclipse.preferences.version=1
gradle.user.home=
java.home=/Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home
jvm.arguments=
offline.mode=false
override.workspace.settings=true
show.console.view=true
show.executions.view=true
2 changes: 1 addition & 1 deletion packages/pigeon/e2e_tests/test_objc/android/app/.classpath
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-10/"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>
12 changes: 7 additions & 5 deletions packages/pigeon/e2e_tests/test_objc/ios/Runner/dartle.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v0.1.0-experimental.11), do not edit directly.
// Autogenerated from Pigeon (v0.1.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon
#import <Foundation/Foundation.h>
@protocol FlutterBinaryMessenger;
Expand Down Expand Up @@ -31,15 +31,17 @@ NS_ASSUME_NONNULL_BEGIN
- (void)search:(ACSearchRequest *)input completion:(void (^)(ACSearchReply *, NSError *))completion;
@end
@protocol ACNestedApi
- (ACSearchReply *)search:(ACNested *)input error:(FlutterError *_Nullable *_Nonnull)error;
- (nullable ACSearchReply *)search:(ACNested *)input error:(FlutterError *_Nullable *_Nonnull)error;
@end

extern void ACNestedApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<ACNestedApi> api);
extern void ACNestedApiSetup(id<FlutterBinaryMessenger> binaryMessenger,
id<ACNestedApi> _Nullable api);

@protocol ACApi
- (ACSearchReply *)search:(ACSearchRequest *)input error:(FlutterError *_Nullable *_Nonnull)error;
- (nullable ACSearchReply *)search:(ACSearchRequest *)input
error:(FlutterError *_Nullable *_Nonnull)error;
@end

extern void ACApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<ACApi> api);
extern void ACApiSetup(id<FlutterBinaryMessenger> binaryMessenger, id<ACApi> _Nullable api);

NS_ASSUME_NONNULL_END
2 changes: 1 addition & 1 deletion packages/pigeon/e2e_tests/test_objc/ios/Runner/dartle.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v0.1.0-experimental.11), do not edit directly.
// Autogenerated from Pigeon (v0.1.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon
#import "dartle.h"
#import <Flutter/Flutter.h>
Expand Down
43 changes: 30 additions & 13 deletions packages/pigeon/e2e_tests/test_objc/lib/dartle.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Autogenerated from Pigeon (v0.1.0-experimental.11), do not edit directly.
// Autogenerated from Pigeon (v0.1.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import
import 'dart:async';
Expand Down Expand Up @@ -66,18 +66,18 @@ class Nested {

abstract class FlutterSearchApi {
SearchReply search(SearchRequest arg);
}

void FlutterSearchApiSetup(FlutterSearchApi api) {
{
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
'dev.flutter.pigeon.FlutterSearchApi.search', StandardMessageCodec());
channel.setMessageHandler((dynamic message) async {
final Map<dynamic, dynamic> mapMessage = message as Map<dynamic, dynamic>;
final SearchRequest input = SearchRequest._fromMap(mapMessage);
final SearchReply output = api.search(input);
return output._toMap();
});
static void setup(FlutterSearchApi api) {
{
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
'dev.flutter.pigeon.FlutterSearchApi.search', StandardMessageCodec());
channel.setMessageHandler((dynamic message) async {
final Map<dynamic, dynamic> mapMessage =
message as Map<dynamic, dynamic>;
final SearchRequest input = SearchRequest._fromMap(mapMessage);
final SearchReply output = api.search(input);
return output._toMap();
});
}
}
}

Expand Down Expand Up @@ -128,3 +128,20 @@ class Api {
}
}
}

abstract class TestHostApi {
SearchReply search(SearchRequest arg);
static void setup(TestHostApi api) {
{
const BasicMessageChannel<dynamic> channel = BasicMessageChannel<dynamic>(
'dev.flutter.pigeon.Api.search', StandardMessageCodec());
channel.setMockMessageHandler((dynamic message) async {
final Map<dynamic, dynamic> mapMessage =
message as Map<dynamic, dynamic>;
final SearchRequest input = SearchRequest._fromMap(mapMessage);
final SearchReply output = api.search(input);
return <dynamic, dynamic>{'result': output._toMap()};
});
}
}
}
2 changes: 1 addition & 1 deletion packages/pigeon/e2e_tests/test_objc/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class _MyFlutterSearchApi extends FlutterSearchApi {

void main() {
WidgetsFlutterBinding.ensureInitialized();
FlutterSearchApiSetup(_MyFlutterSearchApi());
FlutterSearchApi.setup(_MyFlutterSearchApi());
runApp(MyApp());
}

Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## message.dart

```dart
import 'package:pigeon/pigeon_lib.dart';
import 'package:pigeon/pigeon.dart';
class SearchRequest {
String query;
Expand Down
5 changes: 4 additions & 1 deletion packages/pigeon/lib/ast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class Method extends Node {
/// Represents a collection of [Method]s that are hosted ona given [location].
class Api extends Node {
/// Parametric constructor for [Api].
Api({this.name, this.location, this.methods});
Api({this.name, this.location, this.methods, this.dartHostTestHandler});

/// The name of the API.
String name;
Expand All @@ -42,6 +42,9 @@ class Api extends Node {

/// List of methods inside the API.
List<Method> methods;

/// The name of the Dart test interface to generate to help with testing.
String dartHostTestHandler;
}

/// Represents a field on a [Class].
Expand Down
93 changes: 58 additions & 35 deletions packages/pigeon/lib/dart_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ if (replyMap == null) {
indent.writeln('');
}

void _writeFlutterApi(Indent indent, Api api) {
void _writeFlutterApi(Indent indent, Api api,
{String Function(Method) channelNameFunc, bool isMockHandler = false}) {
assert(api.location == ApiLocation.flutter);
indent.write('abstract class ${api.name} ');
indent.scoped('{', '}', () {
Expand All @@ -69,44 +70,57 @@ void _writeFlutterApi(Indent indent, Api api) {
func.argType == 'void' ? '' : '${func.argType} arg';
indent.writeln('${func.returnType} ${func.name}($argSignature);');
}
});
indent.addln('');
indent.write('void ${api.name}Setup(${api.name} api) ');
indent.scoped('{', '}', () {
for (Method func in api.methods) {
indent.write('');
indent.scoped('{', '}', () {
indent.writeln('const BasicMessageChannel<dynamic> channel =');
indent.inc();
indent.inc();
indent.writeln(
'BasicMessageChannel<dynamic>(\'${makeChannelName(api, func)}\', StandardMessageCodec());');
indent.dec();
indent.dec();
indent.write('channel.setMessageHandler((dynamic message) async ');
indent.scoped('{', '});', () {
final String argType = func.argType;
final String returnType = func.returnType;
indent.write('static void setup(${api.name} api) ');
indent.scoped('{', '}', () {
for (Method func in api.methods) {
indent.write('');
indent.scoped('{', '}', () {
indent.writeln('const BasicMessageChannel<dynamic> channel =');
indent.inc();
indent.inc();
final String channelName = channelNameFunc == null
? makeChannelName(api, func)
: channelNameFunc(func);
indent.writeln(
'final Map<dynamic, dynamic> mapMessage = message as Map<dynamic, dynamic>;');
String call;
if (argType == 'void') {
call = 'api.${func.name}()';
} else {
'BasicMessageChannel<dynamic>(\'$channelName\', StandardMessageCodec());');
indent.dec();
indent.dec();
final String messageHandlerSetter =
isMockHandler ? 'setMockMessageHandler' : 'setMessageHandler';
indent
.write('channel.$messageHandlerSetter((dynamic message) async ');
indent.scoped('{', '});', () {
final String argType = func.argType;
final String returnType = func.returnType;
indent.writeln(
'final $argType input = $argType._fromMap(mapMessage);');
call = 'api.${func.name}(input)';
}
if (returnType == 'void') {
indent.writeln('$call;');
} else {
indent.writeln('final $returnType output = $call;');
indent.writeln('return output._toMap();');
}
'final Map<dynamic, dynamic> mapMessage = message as Map<dynamic, dynamic>;');
String call;
if (argType == 'void') {
call = 'api.${func.name}()';
} else {
indent.writeln(
'final $argType input = $argType._fromMap(mapMessage);');
call = 'api.${func.name}(input)';
}
if (returnType == 'void') {
indent.writeln('$call;');
if (isMockHandler) {
indent.writeln('return <dynamic, dynamic>{};');
}
} else {
indent.writeln('final $returnType output = $call;');
const String returnExpresion = 'output._toMap()';
final String returnStatement = isMockHandler
? 'return <dynamic, dynamic>{\'${Keys.result}\': $returnExpresion};'
: 'return $returnExpresion;';
indent.writeln(returnStatement);
}
});
});
});
}
}
});
});
indent.addln('');
}

/// Generates Dart source code for the given AST represented by [root],
Expand Down Expand Up @@ -166,6 +180,15 @@ void generateDart(Root root, StringSink sink) {
for (Api api in root.apis) {
if (api.location == ApiLocation.host) {
_writeHostApi(indent, api);
if (api.dartHostTestHandler != null) {
final Api mockApi = Api(
name: api.dartHostTestHandler,
methods: api.methods,
location: ApiLocation.flutter);
_writeFlutterApi(indent, mockApi,
channelNameFunc: (Method func) => makeChannelName(api, func),
isMockHandler: true);
}
} else if (api.location == ApiLocation.flutter) {
_writeFlutterApi(indent, api);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/lib/generator_tools.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'dart:mirrors';
import 'ast.dart';

/// The current version of pigeon.
const String pigeonVersion = '0.1.0-experimental.11';
const String pigeonVersion = '0.1.0';

/// Read all the content from [stdin] to a String.
String readStdin() {
Expand Down
10 changes: 5 additions & 5 deletions packages/pigeon/lib/objc_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ void generateObjcHeader(ObjcOptions options, Root root, StringSink sink) {

for (Class klass in root.classes) {
indent.writeln(
'@interface ${_className(options.prefix, klass.name)} : NSObject ');
'@interface ${_className(options.prefix, klass.name)} : NSObject');
for (Field field in klass.fields) {
final HostDatatype hostDatatype = getHostDatatype(
field, root.classes, _objcTypeForDartType,
Expand All @@ -115,20 +115,20 @@ void generateObjcHeader(ObjcOptions options, Root root, StringSink sink) {
final String returnTypeName =
_className(options.prefix, func.returnType);
final String returnType =
func.returnType == 'void' ? 'void' : '$returnTypeName *';
func.returnType == 'void' ? 'void' : 'nullable $returnTypeName *';
if (func.argType == 'void') {
indent.writeln(
'-($returnType)${func.name}:(FlutterError * _Nullable * _Nonnull)error;');
'-($returnType)${func.name}:(FlutterError *_Nullable *_Nonnull)error;');
} else {
final String argType = _className(options.prefix, func.argType);
indent.writeln(
'-($returnType)${func.name}:($argType*)input error:(FlutterError * _Nullable * _Nonnull)error;');
'-($returnType)${func.name}:($argType*)input error:(FlutterError *_Nullable *_Nonnull)error;');
}
}
indent.writeln('@end');
indent.writeln('');
indent.writeln(
'extern void ${apiName}Setup(id<FlutterBinaryMessenger> binaryMessenger, id<$apiName> api);');
'extern void ${apiName}Setup(id<FlutterBinaryMessenger> binaryMessenger, id<$apiName> _Nullable api);');
indent.writeln('');
} else if (api.location == ApiLocation.flutter) {
indent.writeln('@interface $apiName : NSObject');
Expand Down
1 change: 1 addition & 0 deletions packages/pigeon/lib/pigeon.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export 'pigeon_lib.dart';
Loading

0 comments on commit 18b52ae

Please sign in to comment.