Skip to content
This repository has been archived by the owner on Jan 26, 2021. It is now read-only.

Commit

Permalink
changes for 0.3.9
Browse files Browse the repository at this point in the history
- Modify dart_options support so that it supports alternate mixins.
- Move the experimental map implementation to PbMapMixin

For now, new mixins can only be added using a patch:
  - add the new class to the protobuf library
  - add the class to the list in mixin.dart.

[email protected], [email protected]

Review URL: https://chromiumcodereview.appspot.com//1192943003
  • Loading branch information
Brian Slesinsky committed Jun 23, 2015
1 parent e750443 commit 8195898
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 165 deletions.
10 changes: 8 additions & 2 deletions lib/code_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,16 @@ class CodeGenerator extends ProtobufContainer {
void generate({
Map<String, SingleOptionParser> optionParsers,
OutputConfiguration outputConfiguration}) {

var extensions = new ExtensionRegistry();
Dart_options.registerAllExtensions(extensions);

_streamIn
.fold(new BytesBuilder(), (builder, data) => builder..add(data))
.then((builder) => builder.takeBytes())
.then((List<int> bytes) {
var request = new CodeGeneratorRequest.fromBuffer(bytes);
var request =
new CodeGeneratorRequest.fromBuffer(bytes, extensions);
var response = new CodeGeneratorResponse();

// Parse the options in the request. Return the errors is any.
Expand All @@ -41,7 +46,8 @@ class CodeGenerator extends ProtobufContainer {
return;
}

var ctx = new GenerationContext(options, outputConfiguration == null
var ctx = new GenerationContext(options,
outputConfiguration == null
? new DefaultOutputConfiguration() : outputConfiguration);
List<FileGenerator> generators = <FileGenerator>[];
for (FileDescriptorProto file in request.protoFile) {
Expand Down
63 changes: 43 additions & 20 deletions lib/file_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@
part of protoc;

class FileGenerator extends ProtobufContainer {
// This should match the extension in dart_options.proto.
static const int implementMapByDefaultOption = 95333044;

// Returns true if option implement_map_by_default is on for this file.
static bool _shouldImplementMapByDefault(FileDescriptorProto desc) {
if (!desc.hasOptions()) return false;

var val = desc.options.unknownFields.getField(implementMapByDefaultOption);
if (val == null || val.length != 1) return false;

return val.values[0] == 1;
/// Returns the the mixin to use by default in this file,
/// or null for no mixin by default.
static PbMixin _getDefaultMixin(FileDescriptorProto desc) {
if (!desc.hasOptions()) return null;
if (!desc.options.hasExtension(Dart_options.defaultMixin)) {
return null;
}
var name = desc.options.getExtension(Dart_options.defaultMixin);
PbMixin mixin = findMixin(name);
if (mixin == null) {
throw("unknown mixin class: ${name}");
}
return mixin;
}

final FileDescriptorProto _fileDescriptor;
Expand All @@ -29,15 +32,15 @@ class FileGenerator extends ProtobufContainer {
FileGenerator(this._fileDescriptor, this._parent, this._context) {
_context.register(this);

bool implementMap = _shouldImplementMapByDefault(_fileDescriptor);
var defaultMixin = _getDefaultMixin(_fileDescriptor);

// Load and register all enum and message types.
for (EnumDescriptorProto enumType in _fileDescriptor.enumType) {
enumGenerators.add(new EnumGenerator(enumType, this, _context));
}
for (DescriptorProto messageType in _fileDescriptor.messageType) {
messageGenerators.add(
new MessageGenerator(messageType, this, _context, implementMap));
new MessageGenerator(messageType, this, _context, defaultMixin));
}
for (FieldDescriptorProto extension in _fileDescriptor.extension) {
extensionGenerators.add(
Expand Down Expand Up @@ -97,8 +100,12 @@ class FileGenerator extends ProtobufContainer {
"import 'package:protobuf/protobuf.dart';"
);

if (needsMapMixinImport) {
out.println("import 'dart:collection' show MapMixin;");
var mixinImports = findMixinsToImport();
var importNames = mixinImports.keys.toList();
importNames.sort();
for (var imp in importNames) {
var symbols = mixinImports[imp];
out.println("import '${imp}' show ${symbols.join(', ')};");
}

for (String import in _fileDescriptor.dependency) {
Expand Down Expand Up @@ -153,13 +160,29 @@ class FileGenerator extends ProtobufContainer {
}
}

bool get needsMapMixinImport {
for (var m in messageGenerators) {
if (m.needsMapMixinImport) {
return true;
}
/// Returns a map from import names to the Dart symbols to be imported.
Map<String, List<String>> findMixinsToImport() {
var mixins = new Set<PbMixin>();
for (MessageGenerator m in messageGenerators) {
m.addMixinsTo(mixins);
}
return false;

var imports = {};
for (var m in mixins) {
var imp = m.importFrom;
List<String> symbols = imports[imp];
if (symbols == null) {
symbols = [];
imports[imp] = symbols;
}
symbols.add(m.name);
}

for (var imp in imports.keys) {
imports[imp].sort();
}

return imports;
}
}

Expand Down
127 changes: 27 additions & 100 deletions lib/message_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,23 @@ class MessageGenerator extends ProtobufContainer {
'extensionsAreInitialized', 'mergeFromMessage', 'mergeUnknownFields',
'==', 'info_', 'GeneratedMessage', 'Object'];

// List of names that can't be used in a subclass that implements Map.
static final List<String> reservedNamesForMap =
['addAll', 'containsKey', 'containsValue', 'forEach', 'putIfAbsent',
'remove', 'isEmpty', 'isNotEmpty', 'keys', 'length', 'values'];

// This should match the extension in dart_options.proto.
static const int implementMapOption = 95333044;

// Returns true if the implement_map option is turned on for the message.
static bool _shouldImplementMap(DescriptorProto desc, bool defaultValue) {
// Returns the mixin for this message, or null if none.
static PbMixin _getMixin(DescriptorProto desc, PbMixin defaultValue) {
if (!desc.hasOptions()) return defaultValue;
if (!desc.options.hasExtension(Dart_options.mixin)) return defaultValue;

var val = desc.options.unknownFields.getField(implementMapOption);
if (val == null || val.length != 1) return defaultValue;

return val.values[0] == 1;
String name = desc.options.getExtension(Dart_options.mixin);
if (name.isEmpty) return null; // don't use a mixin (override any default)
var mixin = findMixin(name);
if (mixin == null) {
throw("unknown mixin class: ${name}");
}
return mixin;
}

final String classname;
final String fqname;
final bool implementsMap;
final PbMixin mixin;

final ProtobufContainer _parent;
final GenerationContext _context;
Expand All @@ -64,15 +60,15 @@ class MessageGenerator extends ProtobufContainer {

MessageGenerator(
DescriptorProto descriptor, ProtobufContainer parent, this._context,
bool implementMapByDefault)
PbMixin defaultMixin)
: _descriptor = descriptor,
_parent = parent,
classname = (parent.classname == '') ?
descriptor.name : '${parent.classname}_${descriptor.name}',
fqname = (parent == null || parent.fqname == null) ? descriptor.name :
(parent.fqname == '.' ?
'.${descriptor.name}' : '${parent.fqname}.${descriptor.name}'),
implementsMap = _shouldImplementMap(descriptor, implementMapByDefault) {
mixin = _getMixin(descriptor, defaultMixin) {
_context.register(this);

for (EnumDescriptorProto e in _descriptor.enumType) {
Expand All @@ -81,7 +77,7 @@ class MessageGenerator extends ProtobufContainer {

for (DescriptorProto n in _descriptor.nestedType) {
_messageGenerators.add(
new MessageGenerator(n, this, _context, implementMapByDefault));
new MessageGenerator(n, this, _context, defaultMixin));
}

for (FieldDescriptorProto x in _descriptor.extension) {
Expand All @@ -91,14 +87,14 @@ class MessageGenerator extends ProtobufContainer {

String get package => _parent.package;

bool get needsMapMixinImport {
if (implementsMap) return true;

/// Adds all mixins used in this message and any submessages.
void addMixinsTo(Set<PbMixin> output) {
if (mixin != null) {
output.addAll(mixin.findMixinsToApply());
}
for (var m in _messageGenerators) {
if (m.implementsMap) return true;
m.addMixinsTo(output);
}

return false;
}

void initializeFields() {
Expand All @@ -116,8 +112,8 @@ class MessageGenerator extends ProtobufContainer {
_methodNames.addAll(reservedWords);
_methodNames.addAll(reservedNames);

if (implementsMap) {
_methodNames.addAll(reservedNamesForMap);
if (mixin != null) {
_methodNames.addAll(mixin.findReservedNames());
}

for (EnumGenerator e in _enumGenerators) {
Expand All @@ -128,12 +124,13 @@ class MessageGenerator extends ProtobufContainer {
m.generate(out);
}

var implClause = "";
if (implementsMap) {
implClause = " with MapMixin";
var mixinClause = '';
if (mixin != null) {
var mixinNames = mixin.findMixinsToApply().map((m) => m.name);
mixinClause = ' with ${mixinNames.join(", ")}';
}

out.addBlock('class ${classname} extends GeneratedMessage${implClause} {',
out.addBlock('class ${classname} extends GeneratedMessage${mixinClause} {',
'}', ()
{
out.addBlock(
Expand Down Expand Up @@ -223,76 +220,6 @@ class MessageGenerator extends ProtobufContainer {
out.println('static PbList<${classname}>${SP}createRepeated()${SP}=>'
'${SP}new PbList<${classname}>();');


if (implementsMap) {
// clear() is inherited from GeneratedMessage.
// Other map operations are implemented by MapMixin.
out.println('''
@override
operator [] (key) {
if (key is !String) return null;
if (!key.contains(".")) {
var tag = getTagNumber(key);
if (tag == null) return null;
return getField(tag);
}
var keys = key.split('.');
var item = this;
for (var key in keys) {
if (item is !GeneratedMessage) return null;
var tag = item.getTagNumber(key);
if (tag == null) return null;
item = item.getField(tag);
}
return item;
}
@override
operator []= (String key, val) {
if (!key.contains(".")) {
var tag = _mustGetTagNumber(this, key);
setField(tag, val);
return;
}
var keys = key.split('.');
var lastKey = keys.removeLast();
var item = this;
for (var key in keys) {
var tag = _mustGetTagNumber(item, key);
item = item.getField(tag);
if (item is !GeneratedMessage) {
throw new ArgumentError(
"field '\${key}' in \${info._messageName} isn't a GeneratedMessage:");
}
}
var tag = _mustGetTagNumber(item, lastKey);
item.setField(tag, val);
}
_mustGetTagNumber(GeneratedMessage msg, String key) {
var tag = msg.getTagNumber(key);
if (tag == null) {
throw new ArgumentError(
"field '\${key}' not found in \${msg.info_.messageName}");
}
return tag;
}
@override
get keys => info_.byName.keys;
@override
get length => info_.byName.length;
remove(key) {
throw new UnsupportedError("remove() not supported by \${info_.messageName}");
}
''');
}

generateFieldsAccessorsMutators(out);
});
out.println();
Expand Down
2 changes: 2 additions & 0 deletions lib/protoc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import 'dart:async';
import 'dart:io';

import 'package:protobuf/protobuf.dart';
import 'package:protobuf/mixins_meta.dart';
import 'package:path/path.dart' as path;

import 'src/descriptor.pb.dart';
import 'src/plugin.pb.dart';
import 'src/dart_options.pb.dart';

part 'code_generator.dart';
part 'enum_generator.dart';
Expand Down
17 changes: 17 additions & 0 deletions lib/src/dart_options.pb.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
///
// Generated code. Do not modify.
///
library dart_options;

import 'package:fixnum/fixnum.dart';
import 'package:protobuf/protobuf.dart';

class Dart_options {
static final Extension defaultMixin = new Extension('FileOptions', 'defaultMixin', 96128839, GeneratedMessage.OS);
static final Extension mixin = new Extension('MessageOptions', 'mixin', 96128839, GeneratedMessage.OS);
static void registerAllExtensions(ExtensionRegistry registry) {
registry.add(defaultMixin);
registry.add(mixin);
}
}

4 changes: 2 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
name: protoc_plugin
version: 0.3.8
version: 0.3.9
author: Dart Team <[email protected]>
description: Protoc compiler plugin to generate Dart code
homepage: https://github.com/dart-lang/dart-protoc-plugin
environment:
sdk: '>=1.0.0 <2.0.0'
dependencies:
protobuf: '>=0.3.6 <0.4.0'
protobuf: '>=0.3.9 <0.4.0'
path: '>=1.0.0 <2.0.0'
dev_dependencies:
unittest: '>=0.9.0 <0.11.0'
Loading

0 comments on commit 8195898

Please sign in to comment.