Skip to content

Commit

Permalink
Add generic types for strong mode
Browse files Browse the repository at this point in the history
FieldInfo, Extension, and PbList should always be created
with the correct reified type when in strong mode.

This is still experimental (not tested with DDC).

BUG=google#54
[email protected], [email protected]

Review URL: https://chromiumcodereview.appspot.com//1844293003 .
  • Loading branch information
Brian Slesinsky committed Apr 1, 2016
1 parent 2397ffd commit 6d131e3
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 69 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.5.1

* Experimental support for strong mode.

## 0.5.0+1

* Support the latest version of package `fixnum`.
Expand Down
68 changes: 33 additions & 35 deletions lib/src/protobuf/builder_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,22 @@ class BuilderInfo {

BuilderInfo(this.messageName);

void add(int tagNumber, String name, int fieldType,
dynamic defaultOrMaker,
CreateBuilderFunc subBuilder,
ValueOfFunc valueOf) {
void add/*<T>*/(
int tagNumber,
String name,
int fieldType,
dynamic defaultOrMaker,
CreateBuilderFunc subBuilder,
ValueOfFunc valueOf) {
var index = fieldInfo.length;
addField(new FieldInfo(
name, tagNumber, index, fieldType, defaultOrMaker, subBuilder, valueOf));
addField(new FieldInfo/*<T>*/(name, tagNumber, index, fieldType,
defaultOrMaker, subBuilder, valueOf));
}

void addRepeated(int tagNumber, String name, int fieldType,
CheckFunc check,
CreateBuilderFunc subBuilder,
ValueOfFunc valueOf) {
void addRepeated/*<T>*/(int tagNumber, String name, int fieldType,
CheckFunc check, CreateBuilderFunc subBuilder, ValueOfFunc valueOf) {
var index = fieldInfo.length;
addField(new FieldInfo.repeated(
addField(new FieldInfo/*<T>*/ .repeated(
name, tagNumber, index, fieldType, check, subBuilder, valueOf));
}

Expand All @@ -42,41 +43,39 @@ class BuilderInfo {
byName[fi.name] = fi;
}

void a(int tagNumber, String name, int fieldType,
[dynamic defaultOrMaker,
CreateBuilderFunc subBuilder,
ValueOfFunc valueOf]) {
add(tagNumber, name, fieldType,
defaultOrMaker, subBuilder, valueOf);
void a/*<T>*/(int tagNumber, String name, int fieldType,
[dynamic defaultOrMaker,
CreateBuilderFunc subBuilder,
ValueOfFunc valueOf]) {
add/*<T>*/(tagNumber, name, fieldType, defaultOrMaker, subBuilder, valueOf);
}

// Enum.
void e(int tagNumber, String name, int fieldType,
dynamic defaultOrMaker, ValueOfFunc valueOf) {
add(tagNumber, name, fieldType,
defaultOrMaker, null, valueOf);
void e/*<T>*/(int tagNumber, String name, int fieldType,
dynamic defaultOrMaker, ValueOfFunc valueOf) {
add/*<T>*/(tagNumber, name, fieldType, defaultOrMaker, null, valueOf);
}

// Repeated message.
// TODO(skybrian): migrate to pp() and remove.
void m(int tagNumber, String name,
CreateBuilderFunc subBuilder, MakeDefaultFunc makeDefault) {
add(tagNumber, name, PbFieldType._REPEATED_MESSAGE,
makeDefault, subBuilder, null);
void m/*<T>*/(int tagNumber, String name, CreateBuilderFunc subBuilder,
MakeDefaultFunc makeDefault) {
add/*<T>*/(tagNumber, name, PbFieldType._REPEATED_MESSAGE, makeDefault,
subBuilder, null);
}

// Repeated, not a message, group, or enum.
void p(int tagNumber, String name, int fieldType) {
void p/*<T>*/(int tagNumber, String name, int fieldType) {
assert(!_isGroupOrMessage(fieldType) && !_isEnum(fieldType));
addRepeated(tagNumber, name, fieldType,
getCheckFunction(fieldType), null, null);
addRepeated/*<T>*/(
tagNumber, name, fieldType, getCheckFunction(fieldType), null, null);
}

// Repeated message, group, or enum.
void pp(int tagNumber, String name, int fieldType, CheckFunc check,
[CreateBuilderFunc subBuilder, ValueOfFunc valueOf]) {
void pp/*<T>*/(int tagNumber, String name, int fieldType, CheckFunc check,
[CreateBuilderFunc subBuilder, ValueOfFunc valueOf]) {
assert(_isGroupOrMessage(fieldType) || _isEnum(fieldType));
addRepeated(tagNumber, name, fieldType, check, subBuilder, valueOf);
addRepeated/*<T>*/(tagNumber, name, fieldType, check, subBuilder, valueOf);
}

bool containsTagNumber(int tagNumber) => fieldInfo.containsKey(tagNumber);
Expand Down Expand Up @@ -123,22 +122,21 @@ class BuilderInfo {
// TODO(skybrian): perhaps the code generator should insert the FieldInfos
// in tag number order, to avoid sorting them?
_sortedByTag = new List<FieldInfo>.from(fieldInfo.values)
..sort((a, b) => a.tagNumber.compareTo(b.tagNumber));
..sort((a, b) => a.tagNumber.compareTo(b.tagNumber));
return _sortedByTag;
}

GeneratedMessage _makeEmptyMessage(
int tagNumber, ExtensionRegistry extensionRegistry) {
CreateBuilderFunc subBuilderFunc = subBuilder(tagNumber);
if (subBuilderFunc == null && extensionRegistry != null) {
subBuilderFunc = extensionRegistry.getExtension(messageName,
tagNumber).subBuilder;
subBuilderFunc =
extensionRegistry.getExtension(messageName, tagNumber).subBuilder;
}
return subBuilderFunc();
}

_decodeEnum(int tagNumber, ExtensionRegistry registry, int rawValue) {

ValueOfFunc f = valueOfFunc(tagNumber);
if (f == null && registry != null) {
f = registry.getExtension(messageName, tagNumber).valueOf;
Expand Down
2 changes: 1 addition & 1 deletion lib/src/protobuf/extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ part of protobuf;
/**
* An object representing an extension field.
*/
class Extension extends FieldInfo {
class Extension<T> extends FieldInfo<T> {
final String extendee;

Extension(this.extendee, String name, int tagNumber, int fieldType,
Expand Down
10 changes: 5 additions & 5 deletions lib/src/protobuf/extension_field_set.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,19 @@ class _ExtensionFieldSet {
///
/// If it doesn't exist, creates the list and saves the extension.
/// Suitable for public API and decoders.
List _ensureRepeatedField(Extension fi) {
List/*<T>*/ _ensureRepeatedField/*<T>*/(Extension/*<T>*/ fi) {
assert(fi.isRepeated);
assert(fi.extendee == _parent._messageName);

var list = _values[fi.tagNumber];
if (list != null) return list;
if (list != null) return list as List/*<T>*/;

// Add info and create list.
_validateInfo(fi);
list = _parent._message.createRepeatedField(fi.tagNumber, fi);
var newList = fi._createRepeatedField(_parent._message);
_addInfoUnchecked(fi);
_setFieldUnchecked(fi, list);
return list;
_setFieldUnchecked(fi, newList);
return newList;
}

_getFieldOrNull(Extension extension) => _values[extension.tagNumber];
Expand Down
13 changes: 11 additions & 2 deletions lib/src/protobuf/field_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ part of protobuf;
/**
* An object representing a protobuf message field.
*/
class FieldInfo {
class FieldInfo<T> {
final String name;
final int tagNumber;
final int index; // index of the field's value. Null for extensions.
Expand Down Expand Up @@ -46,7 +46,7 @@ class FieldInfo {
[this.valueOf])
: this.type = type,
this.check = check,
this.makeDefault = (() => new PbList(check: check)) {
this.makeDefault = (() => new PbList<T>(check: check)) {
assert(name != null);
assert(tagNumber != null);
assert(_isRepeated(type));
Expand Down Expand Up @@ -121,5 +121,14 @@ class FieldInfo {
}
}

/// Creates a repeated field to be attached to the given message.
///
/// Delegates actual list creation to the message, so that it can
/// be overridden by a mixin.
List<T> _createRepeatedField(GeneratedMessage m) {
assert(isRepeated);
return m.createRepeatedField/*<T>*/(tagNumber, this);
}

String toString() => name;
}
22 changes: 11 additions & 11 deletions lib/src/protobuf/field_set.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ class _FieldSet {
_values = _makeValueList(meta.fieldInfo);

static _makeValueList(Map<int, FieldInfo> infos) {
if (infos.isEmpty) return _emptyList;
return new List(infos.length);
if (infos.isEmpty) return _emptyList;
return new List(infos.length);
}

// Metadata about multiple fields
Expand Down Expand Up @@ -110,14 +110,14 @@ class _FieldSet {
throw new ArgumentError("tag $tagNumber not defined in $_messageName");
}

_getDefault(FieldInfo fi) {
/*T*/ _getDefault/*<T>*/(FieldInfo/*<T>*/ fi) {
if (!fi.isRepeated) return fi.makeDefault();
if (_isReadOnly) return _emptyList;

// TODO(skybrian) we could avoid this by generating another
// method for repeated fields:
// msg.mutableFoo().add(123);
var value = _message.createRepeatedField(fi.tagNumber, fi);
var value = fi._createRepeatedField(_message);
_setNonExtensionFieldUnchecked(fi, value);
return value;
}
Expand Down Expand Up @@ -212,18 +212,18 @@ class _FieldSet {
/// Creates and stores the repeated field if it doesn't exist.
/// If it's an extension and the list doesn't exist, validates and stores it.
/// Suitable for decoders.
List _ensureRepeatedField(FieldInfo fi) {
List/*<T>*/ _ensureRepeatedField/*<T>*/(FieldInfo/*<T>*/ fi) {
assert(!_isReadOnly);
assert(fi.isRepeated);
if (fi.index == null) {
return _ensureExtensions()._ensureRepeatedField(fi);
}
var value = _getFieldOrNull(fi);
if (value != null) return value;
if (value != null) return value as List/*<T>*/;

value = _message.createRepeatedField(fi.tagNumber, fi);
_setNonExtensionFieldUnchecked(fi, value);
return value;
var newValue = fi._createRepeatedField(_message);
_setNonExtensionFieldUnchecked(fi, newValue);
return newValue;
}

/// Sets a non-extended field and fires events.
Expand All @@ -237,7 +237,7 @@ class _FieldSet {
// Generated method implementations

/// The implementation of a generated getter.
_$get(int index, int tagNumber, defaultValue) {
/*T*/ _$get/*<T>*/(int index, int tagNumber, /*T*/ defaultValue) {
assert(_nonExtensionInfo(tagNumber).index == index);
var value = _values[index];
if (value != null) return value;
Expand Down Expand Up @@ -265,7 +265,7 @@ class _FieldSet {
assert(_$check(tagNumber, value));
if (_isReadOnly) {
throw new UnsupportedError(
"attempted to call a setter on a read-only message ($_messageName)");
"attempted to call a setter on a read-only message ($_messageName)");
}
if (value == null) {
_$check(tagNumber, value); // throw exception for null value
Expand Down
3 changes: 1 addition & 2 deletions lib/src/protobuf/field_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ bool _isGroupOrMessage(int fieldType) =>

/// Defines constants and functions for dealing with fieldType bits.
class PbFieldType {

/// Returns the base field type without any of the required, repeated
/// and packed bits.
static int _baseType(int fieldType) =>
Expand Down Expand Up @@ -66,7 +65,7 @@ class PbFieldType {

// Closures commonly used by initializers.
static String _STRING_EMPTY() => '';
static List<int> _BYTES_EMPTY() => new PbList(check: _checkInt);
static List<int> _BYTES_EMPTY() => new PbList<int>(check: _checkInt);
static bool _BOOL_FALSE() => false;
static int _INT_ZERO() => 0;
static double _DOUBLE_ZERO() => 0.0;
Expand Down
17 changes: 6 additions & 11 deletions lib/src/protobuf/generated_message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -217,14 +217,8 @@ abstract class GeneratedMessage {
/// that the protobuf can be encoded correctly, the returned List must
/// validate all items added to it. This can most easily be done
/// using the FieldInfo.check function.
List createRepeatedField(int tagNumber, FieldInfo fi) {
if (fi.check != null) {
// new way
return new PbList(check: fi.check);
} else {
// old way; remove after all generated code is upgraded.
return fi.makeDefault();
}
List/*<T>*/ createRepeatedField/*<T>*/(int tagNumber, FieldInfo/*<T>*/ fi) {
return new PbList/*<T>*/(check: fi.check);
}

/// Returns the value of a field, ignoring any defaults.
Expand All @@ -242,7 +236,8 @@ abstract class GeneratedMessage {
_fieldSet._ensureInfo(tagNumber).readonlyDefault;

/// Returns [:true:] if a value of [extension] is present.
bool hasExtension(Extension extension) => _fieldSet._hasExtensions &&
bool hasExtension(Extension extension) =>
_fieldSet._hasExtensions &&
_fieldSet._extensions._getFieldOrNull(extension) != null;

/// Returns [:true:] if this message has a field associated with [tagNumber].
Expand Down Expand Up @@ -280,8 +275,8 @@ abstract class GeneratedMessage {
void setField(int tagNumber, value) => _fieldSet._setField(tagNumber, value);

/// For generated code only.
$_get(int index, int tagNumber, defaultValue) =>
_fieldSet._$get(index, tagNumber, defaultValue);
/*T*/ $_get/*<T>*/(int index, int tagNumber, /*T*/ defaultValue) =>
_fieldSet._$get/*<T>*/(index, tagNumber, defaultValue);

/// For generated code only.
bool $_has(int index, int tagNumber) => _fieldSet._$has(index, tagNumber);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/protobuf/readonly_message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ abstract class ReadonlyMessageMixin {

void clearField(int tagNumber) => _readonly("clearField");

List createRepeatedField(int tagNumber, FieldInfo fi) {
List/*<T>*/ createRepeatedField/*<T>*/(int tagNumber, FieldInfo/*<T>*/ fi) {
_readonly("createRepeatedField");
return null; // not reached
}
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: protobuf
version: 0.5.0+1
version: 0.5.1
author: Dart Team <[email protected]>
description: Runtime library for protobuf support.
homepage: https://github.com/dart-lang/dart-protobuf
Expand Down

0 comments on commit 6d131e3

Please sign in to comment.