diff --git a/protobuf/CHANGELOG.md b/protobuf/CHANGELOG.md index 76d67370..1133abbf 100644 --- a/protobuf/CHANGELOG.md +++ b/protobuf/CHANGELOG.md @@ -1,3 +1,14 @@ +## 6.0.0 + +* **Breaking:** Hide `PbList` and `PbMap` constructors. It is not possible to + construct these values correctly in user code, so the constructors are now + private. Existing uses of `PbList` can be replaced by `List` and `PbMap` can + be replaced by `Map`. + + For immutable lists and maps, you can use `built_value`. ([#1072]) + +[#1072]: https://github.com/google/protobuf.dart/pull/1072 + ## 5.1.0 * Update default size limit of `CodedBufferReader` from 67,108,864 bytes to diff --git a/protobuf/lib/src/protobuf/field_info.dart b/protobuf/lib/src/protobuf/field_info.dart index 775b3c0f..59c709f9 100644 --- a/protobuf/lib/src/protobuf/field_info.dart +++ b/protobuf/lib/src/protobuf/field_info.dart @@ -144,7 +144,7 @@ class FieldInfo { this.enumValues, this.defaultEnumValue, String? protoName, - }) : makeDefault = (() => PbList(check: check)), + }) : makeDefault = (() => newPbList(check: check)), _protoName = protoName, assert(PbFieldType.isRepeated(type)), assert(!PbFieldType.isEnum(type) || valueOf != null); @@ -169,7 +169,7 @@ class FieldInfo { /// [GeneratedMessage.getField], doesn't create a repeated field. dynamic get readonlyDefault { if (isRepeated) { - return _emptyList ??= PbList.unmodifiable(); + return _emptyList ??= newUnmodifiablePbList(); } return makeDefault!(); } @@ -232,13 +232,13 @@ class FieldInfo { /// Creates a repeated field. PbList _createRepeatedField() { assert(isRepeated); - return PbList(check: check); + return newPbList(check: check); } /// Same as above, but allow a tighter typed [PbList] to be created. PbList _createRepeatedFieldWithType() { assert(isRepeated); - return PbList(check: check); + return newPbList(check: check); } /// Convenience method to thread this FieldInfo's reified type parameter to @@ -303,7 +303,7 @@ class MapFieldInfo extends FieldInfo?> { tagNumber, index, type, - defaultOrMaker: () => PbMap(keyFieldType, valueFieldType), + defaultOrMaker: () => newPbMap(keyFieldType, valueFieldType), defaultEnumValue: defaultEnumValue, protoName: protoName, ) { @@ -319,7 +319,7 @@ class MapFieldInfo extends FieldInfo?> { PbMap _createMapField() { assert(isMapField); - return PbMap(keyFieldType, valueFieldType); + return newPbMap(keyFieldType, valueFieldType); } } diff --git a/protobuf/lib/src/protobuf/field_set.dart b/protobuf/lib/src/protobuf/field_set.dart index e2f03f9e..b458faec 100644 --- a/protobuf/lib/src/protobuf/field_set.dart +++ b/protobuf/lib/src/protobuf/field_set.dart @@ -402,7 +402,7 @@ class FieldSet { assert(fi.isMapField); if (_isReadOnly) { - return PbMap.unmodifiable(fi.keyFieldType, fi.valueFieldType); + return newUnmodifiablePbMap(fi.keyFieldType, fi.valueFieldType); } final map = fi._createMapField(); diff --git a/protobuf/lib/src/protobuf/pb_list.dart b/protobuf/lib/src/protobuf/pb_list.dart index eed80e2e..137ad550 100644 --- a/protobuf/lib/src/protobuf/pb_list.dart +++ b/protobuf/lib/src/protobuf/pb_list.dart @@ -13,6 +13,17 @@ import 'utils.dart'; /// Throws [ArgumentError] or [RangeError] when the item is not valid. typedef CheckFunc = void Function(E? x); +@pragma('dart2js:tryInline') +@pragma('vm:prefer-inline') +@pragma('wasm:prefer-inline') +PbList newPbList({CheckFunc? check}) => PbList._(check: check); + +@pragma('dart2js:tryInline') +@pragma('vm:prefer-inline') +@pragma('wasm:prefer-inline') +PbList newUnmodifiablePbList({CheckFunc? check}) => + PbList._unmodifiable(); + /// A [ListBase] implementation used for protobuf `repeated` fields. class PbList extends ListBase { /// The actual list storing the elements. @@ -35,17 +46,13 @@ class PbList extends ListBase { bool get isFrozen => _isReadOnly; - PbList({CheckFunc? check}) : _wrappedList = [], _check = check; + PbList._({CheckFunc? check}) : _wrappedList = [], _check = check; - PbList.unmodifiable() + PbList._unmodifiable() : _wrappedList = _emptyList, _check = checkNotNull, _isReadOnly = true; - PbList.from(Iterable from) - : _wrappedList = List.of(from), - _check = checkNotNull; - @override @pragma('dart2js:never-inline') void add(E element) { @@ -288,7 +295,7 @@ class PbList extends ListBase { } PbList _deepCopy() { - final newList = PbList(check: _check); + final newList = PbList._(check: _check); final wrappedList = _wrappedList; final newWrappedList = newList._wrappedList; if (wrappedList.isNotEmpty) { diff --git a/protobuf/lib/src/protobuf/pb_map.dart b/protobuf/lib/src/protobuf/pb_map.dart index 00513337..0200f4af 100644 --- a/protobuf/lib/src/protobuf/pb_map.dart +++ b/protobuf/lib/src/protobuf/pb_map.dart @@ -10,6 +10,18 @@ import 'utils.dart'; const mapKeyFieldNumber = 1; const mapValueFieldNumber = 2; +@pragma('dart2js:tryInline') +@pragma('vm:prefer-inline') +@pragma('wasm:prefer-inline') +PbMap newPbMap(int keyFieldType, int valueFieldType) => + PbMap._(keyFieldType, valueFieldType); + +@pragma('dart2js:tryInline') +@pragma('vm:prefer-inline') +@pragma('wasm:prefer-inline') +PbMap newUnmodifiablePbMap(int keyFieldType, int valueFieldType) => + PbMap._unmodifiable(keyFieldType, valueFieldType); + /// A [MapBase] implementation used for protobuf `map` fields. class PbMap extends MapBase { /// Key type of the map. Per proto2 and proto3 specs, this needs to be an @@ -34,9 +46,9 @@ class PbMap extends MapBase { bool _isReadOnly = false; - PbMap(this.keyFieldType, this.valueFieldType) : _wrappedMap = {}; + PbMap._(this.keyFieldType, this.valueFieldType) : _wrappedMap = {}; - PbMap.unmodifiable(this.keyFieldType, this.valueFieldType) + PbMap._unmodifiable(this.keyFieldType, this.valueFieldType) : _wrappedMap = {}, _isReadOnly = true; @@ -114,7 +126,7 @@ class PbMap extends MapBase { } PbMap _deepCopy() { - final newMap = PbMap(keyFieldType, valueFieldType); + final newMap = PbMap._(keyFieldType, valueFieldType); final wrappedMap = _wrappedMap; final newWrappedMap = newMap._wrappedMap; if (PbFieldType.isGroupOrMessage(valueFieldType)) { diff --git a/protobuf/pubspec.yaml b/protobuf/pubspec.yaml index efd87811..b2fa5d54 100644 --- a/protobuf/pubspec.yaml +++ b/protobuf/pubspec.yaml @@ -1,5 +1,5 @@ name: protobuf -version: 5.1.0 +version: 6.0.0 description: >- Runtime library for protocol buffers support. Use with package:protoc_plugin to generate Dart code for your '.proto' files. diff --git a/protobuf/test/list_test.dart b/protobuf/test/list_test.dart index 23e99510..ea95cc8e 100644 --- a/protobuf/test/list_test.dart +++ b/protobuf/test/list_test.dart @@ -2,22 +2,13 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -import 'package:fixnum/fixnum.dart'; -import 'package:protobuf/protobuf.dart'; import 'package:test/test.dart'; -// [ArgumentError] in production mode, [TypeError] in checked. -final invalidArgumentException = predicate( - (e) => e is ArgumentError || e is TypeError, -); -final badArgument = throwsA(invalidArgumentException); - -// Suppress an analyzer warning for a deliberate type mismatch. -T cast(Object? x) => x as T; +import 'mock_util.dart'; void main() { test('testPbList handles basic operations', () { - final lb1 = PbList(); + final lb1 = T().int32s; expect(lb1, []); lb1.add(1); @@ -63,7 +54,7 @@ void main() { }); test('PbList handles range operations', () { - final lb2 = PbList(); + final lb2 = T().int32s; lb2.addAll([1, 2, 3, 4, 5, 6, 7, 8, 9]); expect(lb2.sublist(3, 7), [4, 5, 6, 7]); @@ -89,168 +80,4 @@ void main() { lb2.setRange(5, 6, [88, 99].take(2), 1); expect(lb2, [1, 2, 3, 9, 8, 99]); }); - - test('PbList validates items', () { - expect(() { - // ignore: unnecessary_cast - (PbList() as List).add('hello'); - }, throwsA(TypeMatcher())); - }); - - test('PbList for signed int32 validates items', () { - final List list = PbList(check: getCheckFunction(PbFieldType.P3)); - - expect(() { - list.add(-2147483649); - }, throwsArgumentError); - - expect( - () { - list.add(-2147483648); - }, - returnsNormally, - reason: 'could not add min signed int32 to a PbList', - ); - - expect(() { - list.add(2147483648); - }, throwsArgumentError); - - expect( - () { - list.add(2147483647); - }, - returnsNormally, - reason: 'could not add max signed int32 to a PbList', - ); - }); - - test('PBList for unsigned int32 validates items', () { - final List list = PbList(check: getCheckFunction(PbFieldType.PU3)); - - expect(() { - list.add(-1); - }, throwsArgumentError); - - expect( - () { - list.add(0); - }, - returnsNormally, - reason: 'could not add zero to a PbList', - ); - - expect(() { - list.add(4294967296); - }, throwsArgumentError); - - expect( - () { - list.add(4294967295); - }, - returnsNormally, - reason: 'could not add max unsigned int32 to a PbList', - ); - }); - - test('PbList for float validates items', () { - final List list = PbList(check: getCheckFunction(PbFieldType.PF)); - - expect(() { - list.add(3.4028234663852886E39); - }, throwsArgumentError); - - expect(() { - list.add(-3.4028234663852886E39); - }, throwsArgumentError); - - expect( - () { - list.add(3.4028234663852886E38); - }, - returnsNormally, - reason: 'could not add max float to a PbList', - ); - - expect( - () { - list.add(-3.4028234663852886E38); - }, - returnsNormally, - reason: 'could not add min float to a PbList', - ); - }); - - test('PbList for signed Int64 validates items', () { - final List list = PbList(); - expect(() { - list.add(cast(0)); // not an Int64 - }, badArgument); - - expect( - () { - list.add(Int64(0)); - }, - returnsNormally, - reason: 'could not add Int64(0) to a PbList', - ); - - expect( - () { - list.add(Int64.MAX_VALUE); - }, - returnsNormally, - reason: 'could not add max Int64 to a PbList', - ); - - expect( - () { - list.add(Int64.MIN_VALUE); - }, - returnsNormally, - reason: 'could not add min Int64 to PbList', - ); - }); - - test('PbList for unsigned Int64 validates items', () { - final List list = PbList(); - expect(() { - list.add(cast(0)); // not an Int64 - }, badArgument); - - expect( - () { - list.add(Int64(0)); - }, - returnsNormally, - reason: 'could not add Int64(0) to a PbList', - ); - - // Adding -1 should work because we are storing the bits as-is. - // (It will be interpreted as a positive number.) - // See: https://github.com/google/protobuf.dart/issues/44 - expect( - () { - list.add(Int64(-1)); - }, - returnsNormally, - reason: 'could not add Int64(-1) to a PbList', - ); - - expect( - () { - list.add(Int64.MAX_VALUE); - }, - returnsNormally, - reason: 'could not add max Int64 to a PbList', - ); - - expect( - () { - list.add(Int64.MIN_VALUE); - }, - returnsNormally, - reason: 'could not add min Int64 to a PbList', - ); - }); } diff --git a/protoc_plugin/pubspec.yaml b/protoc_plugin/pubspec.yaml index 3d2c0471..86f35970 100644 --- a/protoc_plugin/pubspec.yaml +++ b/protoc_plugin/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: dart_style: ^3.0.0 fixnum: ^1.0.0 path: ^1.8.0 - protobuf: ^5.0.0 + protobuf: ^6.0.0 pub_semver: ^2.2.0 dev_dependencies: