Sync changes from internal repo. (#82)
* Added fast getters for common types.
* Only pass index instead of both tag and index to accessors.
* Delegate more methods to underlying list in PbList.
Fixes #76.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 00018f2..35a1bc2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.6.1
+
+* Added fast getters for common types.
+* Only pass index instead of both tag and index to accessors.
+* Delegate more methods to underlying list in PbList.
+* Small fixes for Dart 2.0.
+
## 0.6.0
* Added enumValues to FieldInfo. Fixes #63.
diff --git a/lib/meta.dart b/lib/meta.dart
index 340817b..6be707d 100644
--- a/lib/meta.dart
+++ b/lib/meta.dart
@@ -50,6 +50,9 @@
'unknownFields',
'clone',
r'$_get',
+ r'$_getI64',
+ r'$_getN',
+ r'$_getS',
r'$_has',
r'$_setBool',
r'$_setBytes',
diff --git a/lib/protobuf.dart b/lib/protobuf.dart
index 6c4965e..a6d5c1e 100644
--- a/lib/protobuf.dart
+++ b/lib/protobuf.dart
@@ -5,7 +5,7 @@
library protobuf;
import 'dart:async' show Future;
-import 'dart:collection' show ListMixin;
+import 'dart:collection' show ListBase;
import 'dart:convert' show BASE64, JSON, Utf8Codec;
import 'dart:math' as math;
import 'dart:typed_data' show TypedData, Uint8List, ByteData, Endianness;
diff --git a/lib/src/protobuf/builder_info.dart b/lib/src/protobuf/builder_info.dart
index e9d55f9..dec83b9 100644
--- a/lib/src/protobuf/builder_info.dart
+++ b/lib/src/protobuf/builder_info.dart
@@ -7,6 +7,7 @@
/// Per-message type setup.
class BuilderInfo {
final String messageName;
+ final List<FieldInfo> byIndex = <FieldInfo>[];
final Map<int, FieldInfo> fieldInfo = new Map<int, FieldInfo>();
final Map<String, FieldInfo> byTagAsString = <String, FieldInfo>{};
final Map<String, FieldInfo> byName = <String, FieldInfo>{};
@@ -24,9 +25,9 @@
CreateBuilderFunc subBuilder,
ValueOfFunc valueOf,
List<ProtobufEnum> enumValues) {
- var index = fieldInfo.length;
- addField(new FieldInfo<T>(name, tagNumber, index, fieldType, defaultOrMaker,
- subBuilder, valueOf, enumValues));
+ var index = byIndex.length;
+ _addField(new FieldInfo<T>(name, tagNumber, index, fieldType,
+ defaultOrMaker, subBuilder, valueOf, enumValues));
}
void addRepeated<T>(
@@ -37,12 +38,14 @@
CreateBuilderFunc subBuilder,
ValueOfFunc valueOf,
List<ProtobufEnum> enumValues) {
- var index = fieldInfo.length;
- addField(new FieldInfo<T>.repeated(name, tagNumber, index, fieldType, check,
- subBuilder, valueOf, enumValues));
+ var index = byIndex.length;
+ _addField(new FieldInfo<T>.repeated(name, tagNumber, index, fieldType,
+ check, subBuilder, valueOf, enumValues));
}
- void addField(FieldInfo fi) {
+ void _addField(FieldInfo fi) {
+ byIndex.add(fi);
+ assert(byIndex[fi.index] == fi);
fieldInfo[fi.tagNumber] = fi;
byTagAsString["${fi.tagNumber}"] = fi;
byName[fi.name] = fi;
@@ -57,6 +60,33 @@
enumValues);
}
+ /// Adds PbFieldType.OS String with no default value to reduce generated
+ /// code size.
+ void aOS(int tagNumber, String name) {
+ add<String>(tagNumber, name, PbFieldType.OS, null, null, null, null);
+ }
+
+ /// Adds PbFieldType.PS String with no default value.
+ void pPS(int tagNumber, String name) {
+ addRepeated<String>(tagNumber, name, PbFieldType.PS,
+ getCheckFunction(PbFieldType.PS), null, null, null);
+ }
+
+ /// Adds PbFieldType.QS String with no default value.
+ void aQS(int tagNumber, String name) {
+ add<String>(tagNumber, name, PbFieldType.QS, null, null, null, null);
+ }
+
+ /// Adds Int64 field with Int64.ZERO default.
+ void aInt64(int tagNumber, String name) {
+ add<Int64>(tagNumber, name, PbFieldType.O6, Int64.ZERO, null, null, null);
+ }
+
+ /// Adds a boolean with no default value.
+ void aOB(int tagNumber, String name) {
+ add<bool>(tagNumber, name, PbFieldType.OB, null, null, null, null);
+ }
+
// Enum.
void e<T>(int tagNumber, String name, int fieldType, dynamic defaultOrMaker,
ValueOfFunc valueOf, List<ProtobufEnum> enumValues) {
diff --git a/lib/src/protobuf/field_set.dart b/lib/src/protobuf/field_set.dart
index 15e6a25..34e57c9 100644
--- a/lib/src/protobuf/field_set.dart
+++ b/lib/src/protobuf/field_set.dart
@@ -27,13 +27,17 @@
_FieldSet(this._message, BuilderInfo meta, this._eventPlugin)
: this._meta = meta,
- _values = _makeValueList(meta.fieldInfo);
+ _values = _makeValueList(meta.byIndex.length);
- static _makeValueList(Map<int, FieldInfo> infos) {
- if (infos.isEmpty) return const [];
- return new List(infos.length);
+ static _makeValueList(int length) {
+ if (length == 0) return _zeroList;
+ return new List(length);
}
+ // Use a fixed length list and not a constant list to ensure that _values
+ // always has the same implementation type.
+ static List _zeroList = new List(0);
+
// Metadata about multiple fields
String get _messageName => _meta.messageName;
@@ -69,6 +73,9 @@
/// Returns FieldInfo for a non-extension field, or null if not found.
FieldInfo _nonExtensionInfo(int tagNumber) => _meta.fieldInfo[tagNumber];
+ /// Returns FieldInfo for a non-extension field.
+ FieldInfo _nonExtensionInfoByIndex(int index) => _meta.byIndex[index];
+
/// Returns the FieldInfo for a regular or extension field.
/// throws ArgumentException if no info is found.
FieldInfo _ensureInfo(int tagNumber) {
@@ -138,7 +145,7 @@
bool _hasField(int tagNumber) {
var fi = _nonExtensionInfo(tagNumber);
- if (fi != null) return _$has(fi.index, tagNumber);
+ if (fi != null) return _$has(fi.index);
if (!_hasExtensions) return false;
return _extensions._hasField(tagNumber);
}
@@ -235,17 +242,43 @@
// Generated method implementations
/// The implementation of a generated getter.
- T _$get<T>(int index, int tagNumber, T defaultValue) {
- assert(_nonExtensionInfo(tagNumber).index == index);
+ T _$get<T>(int index, T defaultValue) {
var value = _values[index];
if (value != null) return value as T;
if (defaultValue != null) return defaultValue;
- return _getDefault(_nonExtensionInfo(tagNumber)) as T;
+ return _getDefault(_nonExtensionInfoByIndex(index)) as T;
}
- /// The implementation of a generated has method.
- bool _$has(int index, int tagNumber) {
- assert(_nonExtensionInfo(tagNumber).index == index);
+ /// The implementation of a generated getter. Common case for submessages.
+ T _$getN<T>(int index) {
+ var value = _values[index];
+ if (value != null) return value as T;
+ return _getDefault(_nonExtensionInfoByIndex(index)) as T;
+ }
+
+ /// The implementation of a generated getter for String fields.
+ String _$getS(int index, String defaultValue) {
+ var value = _values[index];
+ if (value == null) {
+ if (defaultValue != null) return defaultValue;
+ value = _getDefault(_nonExtensionInfoByIndex(index));
+ }
+ String result = value;
+ return result;
+ }
+
+ /// The implementation of a generated getter for Int64 fields.
+ Int64 _$getI64(int index) {
+ var value = _values[index];
+ if (value == null) {
+ value = _getDefault(_nonExtensionInfoByIndex(index));
+ }
+ Int64 result = value;
+ return result;
+ }
+
+ /// The implementation of a generated 'has' method.
+ bool _$has(int index) {
var value = _values[index];
if (value == null) return false;
if (value is List) return value.isNotEmpty;
@@ -257,25 +290,24 @@
/// In production, does no validation other than a null check.
/// Only handles non-repeated, non-extension fields.
/// Also, doesn't handle enums or messages which need per-type validation.
- void _$set(int index, int tagNumber, value) {
- assert(_nonExtensionInfo(tagNumber).index == index);
- assert(!_nonExtensionInfo(tagNumber).isRepeated);
- assert(_$check(tagNumber, value));
+ void _$set(int index, value) {
+ assert(!_nonExtensionInfoByIndex(index).isRepeated);
+ assert(_$check(index, value));
if (_isReadOnly) {
throw new UnsupportedError(
"attempted to call a setter on a read-only message ($_messageName)");
}
if (value == null) {
- _$check(tagNumber, value); // throw exception for null value
+ _$check(index, value); // throw exception for null value
}
if (_hasObservers) {
- _eventPlugin.beforeSetField(_nonExtensionInfo(tagNumber), value);
+ _eventPlugin.beforeSetField(_nonExtensionInfoByIndex(index), value);
}
_values[index] = value;
}
- bool _$check(int tagNumber, var newValue) {
- _validateField(_nonExtensionInfo(tagNumber), newValue);
+ bool _$check(int index, var newValue) {
+ _validateField(_nonExtensionInfoByIndex(index), newValue);
return true; // Allows use in an assertion.
}
@@ -486,12 +518,16 @@
if (fi.isRepeated) {
if (mustClone) {
+ // fieldValue must be a PbList of GeneratedMessage.
+ PbList<GeneratedMessage> pbList = fieldValue;
// Copy the mapped values to a List to avoid redundant cloning (since
// PbList.addAll iterates over its argument twice).
_ensureRepeatedField(fi)
- .addAll(new List.from(fieldValue.map(_cloneMessage)));
+ .addAll(new List.from(pbList.map(_cloneMessage)));
} else {
- _ensureRepeatedField(fi).addAll(fieldValue);
+ // fieldValue must be at least a PbList.
+ PbList pbList = fieldValue;
+ _ensureRepeatedField(fi).addAll(pbList);
}
return;
}
diff --git a/lib/src/protobuf/generated_message.dart b/lib/src/protobuf/generated_message.dart
index e4657e5..338fbc5 100644
--- a/lib/src/protobuf/generated_message.dart
+++ b/lib/src/protobuf/generated_message.dart
@@ -276,56 +276,65 @@
///
/// Throws an [:ArgumentError:] if [value] is [:null:]. To clear a field of
/// it's current value, use [clearField] instead.
- void setField(int tagNumber, value) => _fieldSet._setField(tagNumber, value);
+ void setField(int tagNumber, value) {
+ _fieldSet._setField(tagNumber, value);
+ return; // ignore: dead_code
+ return; // ignore: dead_code
+ }
/// For generated code only.
- T $_get<T>(int index, int tagNumber, T defaultValue) =>
- _fieldSet._$get<T>(index, tagNumber, defaultValue);
+ T $_get<T>(int index, T defaultValue) =>
+ _fieldSet._$get<T>(index, defaultValue);
/// For generated code only.
- bool $_has(int index, int tagNumber) => _fieldSet._$has(index, tagNumber);
+ T $_getN<T>(int index) => _fieldSet._$getN<T>(index);
/// For generated code only.
- void $_setBool(int index, int tagNumber, bool value) =>
- _fieldSet._$set(index, tagNumber, value);
+ String $_getS(int index, String defaultValue) =>
+ _fieldSet._$getS(index, defaultValue);
/// For generated code only.
- void $_setBytes(int index, int tagNumber, List<int> value) =>
- _fieldSet._$set(index, tagNumber, value);
+ Int64 $_getI64(int index) => _fieldSet._$getI64(index);
/// For generated code only.
- void $_setString(int index, int tagNumber, String value) =>
- _fieldSet._$set(index, tagNumber, value);
+ bool $_has(int index) => _fieldSet._$has(index);
/// For generated code only.
- void $_setFloat(int index, int tagNumber, double value) {
+ void $_setBool(int index, bool value) => _fieldSet._$set(index, value);
+
+ /// For generated code only.
+ void $_setBytes(int index, List<int> value) => _fieldSet._$set(index, value);
+
+ /// For generated code only.
+ void $_setString(int index, String value) => _fieldSet._$set(index, value);
+
+ /// For generated code only.
+ void $_setFloat(int index, double value) {
if (value == null || !_isFloat32(value)) {
- _fieldSet._$check(tagNumber, value);
+ _fieldSet._$check(index, value);
}
- _fieldSet._$set(index, tagNumber, value);
+ _fieldSet._$set(index, value);
}
/// For generated code only.
- void $_setDouble(int index, int tagNumber, double value) =>
- _fieldSet._$set(index, tagNumber, value);
+ void $_setDouble(int index, double value) => _fieldSet._$set(index, value);
/// For generated code only.
- void $_setSignedInt32(int index, int tagNumber, int value) {
+ void $_setSignedInt32(int index, int value) {
if (value == null || !_isSigned32(value)) {
- _fieldSet._$check(tagNumber, value);
+ _fieldSet._$check(index, value);
}
- _fieldSet._$set(index, tagNumber, value);
+ _fieldSet._$set(index, value);
}
/// For generated code only.
- void $_setUnsignedInt32(int index, int tagNumber, int value) {
+ void $_setUnsignedInt32(int index, int value) {
if (value == null || !_isUnsigned32(value)) {
- _fieldSet._$check(tagNumber, value);
+ _fieldSet._$check(index, value);
}
- _fieldSet._$set(index, tagNumber, value);
+ _fieldSet._$set(index, value);
}
/// For generated code only.
- void $_setInt64(int index, int tagNumber, Int64 value) =>
- _fieldSet._$set(index, tagNumber, value);
+ void $_setInt64(int index, Int64 value) => _fieldSet._$set(index, value);
}
diff --git a/lib/src/protobuf/json.dart b/lib/src/protobuf/json.dart
index 6c3afb1..62d276e 100644
--- a/lib/src/protobuf/json.dart
+++ b/lib/src/protobuf/json.dart
@@ -5,11 +5,12 @@
part of protobuf;
Map<String, dynamic> _writeToJsonMap(_FieldSet fs) {
- convertToMap(fieldValue, fieldType) {
+ convertToMap(fieldValue, int fieldType) {
int baseType = PbFieldType._baseType(fieldType);
if (_isRepeated(fieldType)) {
- return new List.from(fieldValue.map((e) => convertToMap(e, baseType)));
+ PbList pbList = fieldValue;
+ return new List.from(pbList.map((e) => convertToMap(e, baseType)));
}
switch (baseType) {
@@ -67,8 +68,10 @@
// (Called recursively on nested messages.)
void _mergeFromJsonMap(
_FieldSet fs, Map<String, dynamic> json, ExtensionRegistry registry) {
- for (String key in json.keys) {
- var fi = fs._meta.byTagAsString[key];
+ Iterable<String> keys = json.keys;
+ var meta = fs._meta;
+ for (String key in keys) {
+ var fi = meta.byTagAsString[key];
if (fi == null) {
if (registry == null) continue; // Unknown tag; skip
fi = registry.getExtension(fs._messageName, int.parse(key));
@@ -83,11 +86,14 @@
}
void _appendJsonList(
- _FieldSet fs, List json, FieldInfo fi, ExtensionRegistry registry) {
+ _FieldSet fs, List jsonList, FieldInfo fi, ExtensionRegistry registry) {
List repeated = fs._ensureRepeatedField(fi);
- var length = json.length;
- for (int i = 0; i < length; ++i) {
- var value = json[i];
+ // Micro optimization. Using "for in" generates the following and iterator
+ // alloc:
+ // for (t1 = J.get$iterator$ax(json), t2 = fi.tagNumber, t3 = fi.type,
+ // t4 = J.getInterceptor$ax(repeated); t1.moveNext$0();)
+ for (int i = 0, len = jsonList.length; i < len; i++) {
+ var value = jsonList[i];
var convertedValue =
_convertJsonValue(fs, value, fi.tagNumber, fi.type, registry);
if (convertedValue != null) {
@@ -99,10 +105,15 @@
void _setJsonField(
_FieldSet fs, json, FieldInfo fi, ExtensionRegistry registry) {
var value = _convertJsonValue(fs, json, fi.tagNumber, fi.type, registry);
- if (value != null) {
+ if (value == null) return;
+ // _convertJsonValue throws exception when it fails to do conversion.
+ // Therefore we run _validateField for debug builds only to validate
+ // correctness of conversion.
+ assert(() {
fs._validateField(fi, value);
- fs._setFieldUnchecked(fi, value);
- }
+ return true;
+ }());
+ fs._setFieldUnchecked(fi, value);
}
/// Converts [value] from the Json format to the Dart data type
@@ -185,16 +196,16 @@
case PbFieldType._FIXED64_BIT:
case PbFieldType._SFIXED64_BIT:
if (value is int) return new Int64(value);
- if (value is String) return Int64.parseRadix(value, 10);
+ if (value is String) return Int64.parseInt(value);
expectedType = 'int or stringified int';
break;
case PbFieldType._GROUP_BIT:
case PbFieldType._MESSAGE_BIT:
if (value is Map) {
+ Map<String, dynamic> messageValue = value;
GeneratedMessage subMessage =
fs._meta._makeEmptyMessage(tagNumber, registry);
- _mergeFromJsonMap(
- subMessage._fieldSet, value as Map<String, dynamic>, registry);
+ _mergeFromJsonMap(subMessage._fieldSet, messageValue, registry);
return subMessage;
}
expectedType = 'nested message or group';
diff --git a/lib/src/protobuf/mixins/map_mixin.dart b/lib/src/protobuf/mixins/map_mixin.dart
index 0032552..7079aa4 100644
--- a/lib/src/protobuf/mixins/map_mixin.dart
+++ b/lib/src/protobuf/mixins/map_mixin.dart
@@ -6,12 +6,13 @@
import "package:protobuf/protobuf.dart" show BuilderInfo;
-/// A PbMapMixin provides an experimental implementation of the
-/// Map interface for a GeneratedMessage.
+/// Note that this class does not claim to implement [Map]. Instead, this needs
+/// to be specified using a dart_options.imports clause specifying MapMixin as a
+/// parent mixin to PbMapMixin.
///
-/// This mixin is enabled via an option in
-/// dart_options.proto in dart-protoc-plugin.
-abstract class PbMapMixin implements Map {
+/// Since PbMapMixin is built in, this is done automatically, so this mixin can
+/// be enabled by specifying only a dart_options.mixin option.
+abstract class PbMapMixin {
// GeneratedMessage properties and methods used by this mixin.
BuilderInfo get info_;
@@ -20,7 +21,6 @@
getField(int tagNumber);
void setField(int tagNumber, var value);
- @override
operator [](key) {
if (key is! String) return null;
var tag = getTagNumber(key);
@@ -28,7 +28,6 @@
return getField(tag);
}
- @override
operator []=(key, val) {
var tag = getTagNumber(key as String);
if (tag == null) {
@@ -38,16 +37,12 @@
setField(tag, val);
}
- @override
- get keys => info_.byName.keys;
+ Iterable<String> get keys => info_.byName.keys;
- @override
bool containsKey(Object key) => info_.byName.containsKey(key);
- @override
- get length => info_.byName.length;
+ int get length => info_.byName.length;
- @override
remove(key) {
throw new UnsupportedError(
"remove() not supported by ${info_.messageName}");
diff --git a/lib/src/protobuf/pb_list.dart b/lib/src/protobuf/pb_list.dart
index 9176a82..85f7025 100644
--- a/lib/src/protobuf/pb_list.dart
+++ b/lib/src/protobuf/pb_list.dart
@@ -6,7 +6,7 @@
typedef void CheckFunc<E>(E x);
-class PbList<E> extends Object with ListMixin<E> implements List<E> {
+class PbList<E> extends ListBase<E> {
final List<E> _wrappedList;
final CheckFunc<E> check;
@@ -44,11 +44,93 @@
/// `f` on each element of this `PbList` in iteration order.
Iterable<T> map<T>(T f(E e)) => _wrappedList.map<T>(f);
+ /// Returns a new lazy [Iterable] with all elements that satisfy the predicate
+ /// [test].
+ Iterable<E> where(bool test(E element)) => _wrappedList.where(test);
+
+ /// Expands each element of this [Iterable] into zero or more elements.
+ Iterable<T> expand<T>(Iterable<T> f(E element)) => _wrappedList.expand(f);
+
+ /// Returns true if the collection contains an element equal to [element].
+ bool contains(Object element) => _wrappedList.contains(element);
+
/// Applies the function [f] to each element of this list in iteration order.
void forEach(void f(E element)) {
_wrappedList.forEach(f);
}
+ /// Reduces a collection to a single value by iteratively combining elements
+ /// of the collection using the provided function.
+ E reduce(E combine(E value, E element)) => _wrappedList.reduce(combine);
+
+ /// Reduces a collection to a single value by iteratively combining each
+ /// element of the collection with an existing value.
+ T fold<T>(T initialValue, T combine(dynamic previousValue, E element)) =>
+ _wrappedList.fold(initialValue, combine);
+
+ /// Checks whether every element of this iterable satisfies [test].
+ bool every(bool test(E element)) => _wrappedList.every(test);
+
+ /// Converts each element to a [String] and concatenates the strings.
+ String join([String separator = ""]) => _wrappedList.join(separator);
+
+ /// Checks whether any element of this iterable satisfies [test].
+ bool any(bool test(E element)) => _wrappedList.any(test);
+
+ /// Creates a [List] containing the elements of this [Iterable].
+ List<E> toList({bool growable: true}) =>
+ _wrappedList.toList(growable: growable);
+
+ /// Creates a [Set] containing the same elements as this iterable.
+ Set<E> toSet() => _wrappedList.toSet();
+
+ /// Returns `true` if there are no elements in this collection.
+ bool get isEmpty => _wrappedList.isEmpty;
+
+ /// Returns `true` if there is at least one element in this collection.
+ bool get isNotEmpty => _wrappedList.isNotEmpty;
+
+ /// Returns a lazy iterable of the [count] first elements of this iterable.
+ Iterable<E> take(int count) => _wrappedList.take(count);
+
+ /// Returns a lazy iterable of the leading elements satisfying [test].
+ Iterable<E> takeWhile(bool test(E value)) => _wrappedList.takeWhile(test);
+
+ /// Returns an [Iterable] that provides all but the first [count] elements.
+ Iterable<E> skip(int count) => _wrappedList.skip(count);
+
+ /// Returns an `Iterable` that skips leading elements while [test] is
+ /// satisfied.
+ Iterable<E> skipWhile(bool test(E value)) => _wrappedList.skipWhile(test);
+
+ /// Returns the first element.
+ E get first => _wrappedList.first;
+
+ /// Returns the last element.
+ E get last => _wrappedList.last;
+
+ /// Checks that this iterable has only one element, and returns that element.
+ E get single => _wrappedList.single;
+
+ /// Returns the first element that satisfies the given predicate [test].
+ E firstWhere(bool test(E element), {E orElse()}) =>
+ _wrappedList.firstWhere(test, orElse: orElse);
+
+ /// Returns the last element that satisfies the given predicate [test].
+ E lastWhere(bool test(E element), {E orElse()}) =>
+ _wrappedList.lastWhere(test, orElse: orElse);
+
+ /// Returns the single element that satisfies [test].
+ // TODO(jakobr): Implement once Dart 2 corelib changes have landed.
+ //E singleWhere(bool test(E element), {E orElse()}) =>
+ // _wrappedList.singleWhere(test, orElse: orElse);
+
+ /// Returns the [index]th element.
+ E elementAt(int index) => _wrappedList.elementAt(index);
+
+ /// Returns a string representation of (some of) the elements of `this`.
+ String toString() => _wrappedList.toString();
+
/// Returns the element at the given [index] in the list or throws an
/// [IndexOutOfRangeException] if [index] is out of bounds.
E operator [](int index) => _wrappedList[index];
@@ -60,14 +142,17 @@
_wrappedList[index] = value;
}
+ /// Returns the number of elements in this collection.
+ int get length => _wrappedList.length;
+
/// Unsupported -- violated non-null constraint imposed by protobufs.
///
/// Changes the length of the list. If [newLength] is greater than the current
/// [length], entries are initialized to [:null:]. Throws an
/// [UnsupportedError] if the list is not extendable.
- void set length(int newLength) {
+ set length(int newLength) {
if (newLength > length) {
- throw new ArgumentError('Extending protobuf lists is not supported');
+ throw new UnsupportedError('Extending protobuf lists is not supported');
}
_wrappedList.length = newLength;
}
@@ -87,15 +172,28 @@
_wrappedList.addAll(collection);
}
- /// Copies [:end - start:] elements of the [from] array, starting from
- /// [skipCount], into [:this:], starting at [start].
- /// Throws an [UnsupportedError] if the list is not extendable.
- void setRange(int start, int end, Iterable<E> from, [int skipCount = 0]) {
- // NOTE: In case `take()` returns less than `end - start` elements, the
- // _wrappedList will fail with a `StateError`.
- from.skip(skipCount).take(end - start).forEach(_validate);
- _wrappedList.setRange(start, end, from, skipCount);
- }
+ /// Returns an [Iterable] of the objects in this list in reverse order.
+ Iterable<E> get reversed => _wrappedList.reversed;
+
+ /// Sorts this list according to the order specified by the [compare]
+ /// function.
+ void sort([int compare(E a, E b)]) => _wrappedList.sort(compare);
+
+ /// Shuffles the elements of this list randomly.
+ void shuffle([math.Random random]) => _wrappedList.shuffle(random);
+
+ // TODO(jakobr): E instead of Object once dart-lang/sdk#31311 is fixed.
+ /// Returns the first index of [element] in this list.
+ int indexOf(Object element, [int start = 0]) =>
+ _wrappedList.indexOf(element, start);
+
+ // TODO(jakobr): E instead of Object once dart-lang/sdk#31311 is fixed.
+ /// Returns the last index of [element] in this list.
+ int lastIndexOf(Object element, [int start]) =>
+ _wrappedList.lastIndexOf(element, start);
+
+ /// Removes all objects from this list; the length of the list becomes zero.
+ void clear() => _wrappedList.clear();
/// Inserts a new element in the list.
/// The element must be valid (and not nullable) for the PbList type.
@@ -121,8 +219,59 @@
_wrappedList.setAll(index, iterable);
}
- /// Returns the number of elements in this collection.
- int get length => _wrappedList.length;
+ /// Removes the first occurrence of [value] from this list.
+ bool remove(Object value) => _wrappedList.remove(value);
+
+ /// Removes the object at position [index] from this list.
+ E removeAt(int index) => _wrappedList.removeAt(index);
+
+ /// Pops and returns the last object in this list.
+ E removeLast() => _wrappedList.removeLast();
+
+ /// Removes all objects from this list that satisfy [test].
+ void removeWhere(bool test(E element)) => _wrappedList.removeWhere(test);
+
+ /// Removes all objects from this list that fail to satisfy [test].
+ void retainWhere(bool test(E element)) => _wrappedList.retainWhere(test);
+
+ /// Returns a new list containing the objects from [start] inclusive to [end]
+ /// exclusive.
+ List<E> sublist(int start, [int end]) => _wrappedList.sublist(start, end);
+
+ /// Returns an [Iterable] that iterates over the objects in the range [start]
+ /// inclusive to [end] exclusive.
+ Iterable<E> getRange(int start, int end) => _wrappedList.getRange(start, end);
+
+ /// Copies [:end - start:] elements of the [from] array, starting from
+ /// [skipCount], into [:this:], starting at [start].
+ /// Throws an [UnsupportedError] if the list is not extendable.
+ void setRange(int start, int end, Iterable<E> from, [int skipCount = 0]) {
+ // NOTE: In case `take()` returns less than `end - start` elements, the
+ // _wrappedList will fail with a `StateError`.
+ from.skip(skipCount).take(end - start).forEach(_validate);
+ _wrappedList.setRange(start, end, from, skipCount);
+ }
+
+ /// Removes the objects in the range [start] inclusive to [end] exclusive.
+ void removeRange(int start, int end) => _wrappedList.removeRange(start, end);
+
+ /// Sets the objects in the range [start] inclusive to [end] exclusive to the
+ /// given [fillValue].
+ void fillRange(int start, int end, [E fillValue]) {
+ _validate(fillValue);
+ _wrappedList.fillRange(start, end, fillValue);
+ }
+
+ /// Removes the objects in the range [start] inclusive to [end] exclusive and
+ /// inserts the contents of [replacement] in its place.
+ void replaceRange(int start, int end, Iterable<E> replacement) {
+ final values = replacement.toList();
+ replacement.forEach(_validate);
+ _wrappedList.replaceRange(start, end, values);
+ }
+
+ /// Returns an unmodifiable [Map] view of `this`.
+ Map<int, E> asMap() => _wrappedList.asMap();
void _validate(E val) {
check(val);
diff --git a/pubspec.yaml b/pubspec.yaml
index 3b2adb9..32a55c8 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: protobuf
-version: 0.6.0
+version: 0.6.1
author: Dart Team <misc@dartlang.org>
description: Runtime library for protocol buffers support.
homepage: https://github.com/dart-lang/protobuf
diff --git a/test/mock_util.dart b/test/mock_util.dart
index b67bf8d..8b58b92 100644
--- a/test/mock_util.dart
+++ b/test/mock_util.dart
@@ -22,18 +22,18 @@
// subclasses must provide these
BuilderInfo get info_;
- int get val => $_get(0, 1, 42);
+ int get val => $_get(0, 42);
set val(x) => setField(1, x);
- String get str => $_get(1, 2, "");
- set str(x) => $_setString(1, 2, x);
+ String get str => $_getS(1, "");
+ set str(x) => $_setString(1, x);
- MockMessage get child => $_get(2, 3, null);
+ MockMessage get child => $_getN(2);
set child(x) => setField(3, x);
- List<int> get int32s => $_get(3, 4, null);
+ List<int> get int32s => $_getN(3);
- Int64 get int64 => $_get(4, 5, new Int64(0));
+ Int64 get int64 => $_get(4, new Int64(0));
set int64(x) => setField(5, x);
clone() {