Skip to content

Commit

Permalink
[pigeon] removes generated codecs if there are no custom datatypes (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
tarrinneal authored Oct 7, 2022
1 parent cb936e2 commit c3d7574
Show file tree
Hide file tree
Showing 19 changed files with 855 additions and 323 deletions.
4 changes: 4 additions & 0 deletions packages/pigeon/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 4.2.2

* Removes unneeded custom codecs for all languages.

## 4.2.1

* Adds documentation comment support for Kotlin.
Expand Down
136 changes: 72 additions & 64 deletions packages/pigeon/lib/cpp_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const String _commentPrefix = '//';
const DocumentCommentSpecification _docCommentSpec =
DocumentCommentSpecification(_commentPrefix);

/// The default serializer for Flutter.
const String _defaultCodecSerializer = 'flutter::StandardCodecSerializer';

/// Options that control how C++ code will be generated.
class CppOptions {
/// Creates a [CppOptions] object
Expand Down Expand Up @@ -61,83 +64,80 @@ class CppOptions {
}
}

String _getCodecName(Api api) => '${api.name}CodecSerializer';
String _getCodecSerializerName(Api api) => '${api.name}CodecSerializer';

const String _pointerPrefix = 'pointer';
const String _encodablePrefix = 'encodable';

void _writeCodecHeader(Indent indent, Api api, Root root) {
final String codecName = _getCodecName(api);
indent.write('class $codecName : public flutter::StandardCodecSerializer ');
assert(getCodecClasses(api, root).isNotEmpty);
final String codeSerializerName = _getCodecSerializerName(api);
indent.write('class $codeSerializerName : public $_defaultCodecSerializer ');
indent.scoped('{', '};', () {
indent.scoped(' public:', '', () {
indent.writeln('');
indent.format('''
inline static $codecName& GetInstance() {
\tstatic $codecName sInstance;
inline static $codeSerializerName& GetInstance() {
\tstatic $codeSerializerName sInstance;
\treturn sInstance;
}
''');
indent.writeln('$codecName();');
indent.writeln('$codeSerializerName();');
});
indent.writeScoped(' public:', '', () {
indent.writeln(
'void WriteValue(const flutter::EncodableValue& value, flutter::ByteStreamWriter* stream) const override;');
});
indent.writeScoped(' protected:', '', () {
indent.writeln(
'flutter::EncodableValue ReadValueOfType(uint8_t type, flutter::ByteStreamReader* stream) const override;');
});
if (getCodecClasses(api, root).isNotEmpty) {
indent.writeScoped(' public:', '', () {
indent.writeln(
'void WriteValue(const flutter::EncodableValue& value, flutter::ByteStreamWriter* stream) const override;');
});
indent.writeScoped(' protected:', '', () {
indent.writeln(
'flutter::EncodableValue ReadValueOfType(uint8_t type, flutter::ByteStreamReader* stream) const override;');
});
}
}, nestCount: 0);
}

void _writeCodecSource(Indent indent, Api api, Root root) {
final String codecName = _getCodecName(api);
indent.writeln('$codecName::$codecName() {}');
if (getCodecClasses(api, root).isNotEmpty) {
indent.write(
'flutter::EncodableValue $codecName::ReadValueOfType(uint8_t type, flutter::ByteStreamReader* stream) const ');
assert(getCodecClasses(api, root).isNotEmpty);
final String codeSerializerName = _getCodecSerializerName(api);
indent.writeln('$codeSerializerName::$codeSerializerName() {}');
indent.write(
'flutter::EncodableValue $codeSerializerName::ReadValueOfType(uint8_t type, flutter::ByteStreamReader* stream) const ');
indent.scoped('{', '}', () {
indent.write('switch (type) ');
indent.scoped('{', '}', () {
indent.write('switch (type) ');
indent.scoped('{', '}', () {
for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
indent.write('case ${customClass.enumeration}:');
indent.writeScoped('', '', () {
indent.writeln(
'return flutter::CustomEncodableValue(${customClass.name}(std::get<flutter::EncodableMap>(ReadValue(stream))));');
});
}
indent.write('default:');
for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
indent.write('case ${customClass.enumeration}:');
indent.writeScoped('', '', () {
indent.writeln(
'return flutter::StandardCodecSerializer::ReadValueOfType(type, stream);');
}, addTrailingNewline: false);
});
'return flutter::CustomEncodableValue(${customClass.name}(std::get<flutter::EncodableMap>(ReadValue(stream))));');
});
}
indent.write('default:');
indent.writeScoped('', '', () {
indent.writeln(
'return $_defaultCodecSerializer::ReadValueOfType(type, stream);');
}, addTrailingNewline: false);
});
indent.writeln('');
});
indent.writeln('');
indent.write(
'void $codeSerializerName::WriteValue(const flutter::EncodableValue& value, flutter::ByteStreamWriter* stream) const ');
indent.writeScoped('{', '}', () {
indent.write(
'void $codecName::WriteValue(const flutter::EncodableValue& value, flutter::ByteStreamWriter* stream) const ');
indent.writeScoped('{', '}', () {
indent.write(
'if (const flutter::CustomEncodableValue* custom_value = std::get_if<flutter::CustomEncodableValue>(&value)) ');
indent.scoped('{', '}', () {
for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
indent.write(
'if (custom_value->type() == typeid(${customClass.name})) ');
indent.scoped('{', '}', () {
indent.writeln('stream->WriteByte(${customClass.enumeration});');
indent.writeln(
'WriteValue(std::any_cast<${customClass.name}>(*custom_value).ToEncodableMap(), stream);');
indent.writeln('return;');
});
}
});
indent.writeln(
'flutter::StandardCodecSerializer::WriteValue(value, stream);');
'if (const flutter::CustomEncodableValue* custom_value = std::get_if<flutter::CustomEncodableValue>(&value)) ');
indent.scoped('{', '}', () {
for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
indent
.write('if (custom_value->type() == typeid(${customClass.name})) ');
indent.scoped('{', '}', () {
indent.writeln('stream->WriteByte(${customClass.enumeration});');
indent.writeln(
'WriteValue(std::any_cast<${customClass.name}>(*custom_value).ToEncodableMap(), stream);');
indent.writeln('return;');
});
}
});
}
indent.writeln('$_defaultCodecSerializer::WriteValue(value, stream);');
});
}

void _writeErrorOr(Indent indent,
Expand Down Expand Up @@ -245,7 +245,7 @@ void _writeDataClassDeclaration(Indent indent, Class klass, Root root,
// TODO(gaaclarke): Find a way to be more precise with our
// friendships.
indent.writeln('friend class ${api.name};');
indent.writeln('friend class ${_getCodecName(api)};');
indent.writeln('friend class ${_getCodecSerializerName(api)};');
}
if (testFriend != null) {
indent.writeln('friend class $testFriend;');
Expand Down Expand Up @@ -484,11 +484,13 @@ void _writeHostApiHeader(Indent indent, Api api, Root root) {
void _writeHostApiSource(Indent indent, Api api, Root root) {
assert(api.location == ApiLocation.host);

final String codecName = _getCodecName(api);
final String codeSerializerName = getCodecClasses(api, root).isNotEmpty
? _getCodecSerializerName(api)
: _defaultCodecSerializer;
indent.format('''
/// The codec used by ${api.name}.
const flutter::StandardMessageCodec& ${api.name}::GetCodec() {
\treturn flutter::StandardMessageCodec::GetInstance(&$codecName::GetInstance());
\treturn flutter::StandardMessageCodec::GetInstance(&$codeSerializerName::GetInstance());
}
''');
indent.writeln(
Expand Down Expand Up @@ -740,7 +742,7 @@ void _writeFlutterApiHeader(Indent indent, Api api) {
}, nestCount: 0);
}

void _writeFlutterApiSource(Indent indent, Api api) {
void _writeFlutterApiSource(Indent indent, Api api, Root root) {
assert(api.location == ApiLocation.flutter);
indent.writeln(
'$_commentPrefix Generated class from Pigeon that represents Flutter messages that can be called from C++.');
Expand All @@ -750,10 +752,12 @@ void _writeFlutterApiSource(Indent indent, Api api) {
indent.writeln('this->binary_messenger_ = binary_messenger;');
});
indent.writeln('');
final String codecName = _getCodecName(api);
final String codeSerializerName = getCodecClasses(api, root).isNotEmpty
? _getCodecSerializerName(api)
: _defaultCodecSerializer;
indent.format('''
const flutter::StandardMessageCodec& ${api.name}::GetCodec() {
\treturn flutter::StandardMessageCodec::GetInstance(&$codecName::GetInstance());
\treturn flutter::StandardMessageCodec::GetInstance(&$codeSerializerName::GetInstance());
}
''');
for (final Method func in api.methods) {
Expand Down Expand Up @@ -1081,7 +1085,9 @@ void generateCppHeader(
}

for (final Api api in root.apis) {
_writeCodecHeader(indent, api, root);
if (getCodecClasses(api, root).isNotEmpty) {
_writeCodecHeader(indent, api, root);
}
indent.addln('');
if (api.location == ApiLocation.host) {
_writeHostApiHeader(indent, api, root);
Expand Down Expand Up @@ -1135,8 +1141,10 @@ void generateCppSource(CppOptions options, Root root, StringSink sink) {
}

for (final Api api in root.apis) {
_writeCodecSource(indent, api, root);
indent.addln('');
if (getCodecClasses(api, root).isNotEmpty) {
_writeCodecSource(indent, api, root);
indent.addln('');
}
if (api.location == ApiLocation.host) {
_writeHostApiSource(indent, api, root);

Expand All @@ -1158,7 +1166,7 @@ flutter::EncodableMap ${api.name}::WrapError(const FlutterError& error) {
}''');
indent.addln('');
} else if (api.location == ApiLocation.flutter) {
_writeFlutterApiSource(indent, api);
_writeFlutterApiSource(indent, api, root);
}
}

Expand Down
75 changes: 41 additions & 34 deletions packages/pigeon/lib/dart_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ const String _docCommentPrefix = '///';
const DocumentCommentSpecification _docCommentSpec =
DocumentCommentSpecification(_docCommentPrefix);

/// The standard codec for Flutter, used for any non custom codecs and extended for custom codecs.
const String _standardMessageCodec = 'StandardMessageCodec';

/// Options that control how Dart code will be generated.
class DartOptions {
/// Constructor for DartOptions.
Expand Down Expand Up @@ -67,44 +70,43 @@ String _getCodecName(Api api) => '_${api.name}Codec';
///
/// class FooCodec extends StandardMessageCodec {...}
void _writeCodec(Indent indent, String codecName, Api api, Root root) {
indent.write('class $codecName extends StandardMessageCodec ');
assert(getCodecClasses(api, root).isNotEmpty);
final Iterable<EnumeratedClass> codecClasses = getCodecClasses(api, root);
indent.write('class $codecName extends $_standardMessageCodec');
indent.scoped('{', '}', () {
indent.writeln('const $codecName();');
if (getCodecClasses(api, root).isNotEmpty) {
indent.writeln('@override');
indent.write('void writeValue(WriteBuffer buffer, Object? value) ');
indent.scoped('{', '}', () {
for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
indent.write('if (value is ${customClass.name}) ');
indent.scoped('{', '} else ', () {
indent.writeln('buffer.putUint8(${customClass.enumeration});');
indent.writeln('writeValue(buffer, value.encode());');
});
}
indent.scoped('{', '}', () {
indent.writeln('super.writeValue(buffer, value);');
indent.writeln('@override');
indent.write('void writeValue(WriteBuffer buffer, Object? value) ');
indent.scoped('{', '}', () {
for (final EnumeratedClass customClass in codecClasses) {
indent.write('if (value is ${customClass.name}) ');
indent.scoped('{', '} else ', () {
indent.writeln('buffer.putUint8(${customClass.enumeration});');
indent.writeln('writeValue(buffer, value.encode());');
});
}
indent.scoped('{', '}', () {
indent.writeln('super.writeValue(buffer, value);');
});
indent.writeln('@override');
indent.write('Object? readValueOfType(int type, ReadBuffer buffer) ');
});
indent.writeln('@override');
indent.write('Object? readValueOfType(int type, ReadBuffer buffer) ');
indent.scoped('{', '}', () {
indent.write('switch (type) ');
indent.scoped('{', '}', () {
indent.write('switch (type) ');
indent.scoped('{', '}', () {
for (final EnumeratedClass customClass
in getCodecClasses(api, root)) {
indent.write('case ${customClass.enumeration}: ');
indent.writeScoped('', '', () {
indent.writeln(
'return ${customClass.name}.decode(readValue(buffer)!);');
});
}
indent.write('default:');
for (final EnumeratedClass customClass in codecClasses) {
indent.write('case ${customClass.enumeration}: ');
indent.writeScoped('', '', () {
indent.writeln('return super.readValueOfType(type, buffer);');
indent.writeln(
'return ${customClass.name}.decode(readValue(buffer)!);');
});
}
indent.write('default:');
indent.writeScoped('', '', () {
indent.writeln('return super.readValueOfType(type, buffer);');
});
});
}
});
});
}

Expand Down Expand Up @@ -157,8 +159,11 @@ String _getMethodArgumentsSignature(
/// }
void _writeHostApi(DartOptions opt, Indent indent, Api api, Root root) {
assert(api.location == ApiLocation.host);
final String codecName = _getCodecName(api);
_writeCodec(indent, codecName, api, root);
String codecName = _standardMessageCodec;
if (getCodecClasses(api, root).isNotEmpty) {
codecName = _getCodecName(api);
_writeCodec(indent, codecName, api, root);
}
indent.addln('');
bool first = true;
addDocumentationComments(indent, api.documentationComments, _docCommentSpec);
Expand All @@ -169,7 +174,6 @@ void _writeHostApi(DartOptions opt, Indent indent, Api api, Root root) {
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
${api.name}({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger;
final BinaryMessenger? _binaryMessenger;
''');

Expand Down Expand Up @@ -272,8 +276,11 @@ void _writeFlutterApi(
bool isMockHandler = false,
}) {
assert(api.location == ApiLocation.flutter);
final String codecName = _getCodecName(api);
_writeCodec(indent, codecName, api, root);
String codecName = _standardMessageCodec;
if (getCodecClasses(api, root).isNotEmpty) {
codecName = _getCodecName(api);
_writeCodec(indent, codecName, api, root);
}
addDocumentationComments(indent, api.documentationComments, _docCommentSpec);

indent.write('abstract class ${api.name} ');
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 @@ -9,7 +9,7 @@ import 'dart:mirrors';
import 'ast.dart';

/// The current version of pigeon. This must match the version in pubspec.yaml.
const String pigeonVersion = '4.2.1';
const String pigeonVersion = '4.2.2';

/// Read all the content from [stdin] to a String.
String readStdin() {
Expand Down
Loading

0 comments on commit c3d7574

Please sign in to comment.