Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion protobuf/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## 5.1.0-wip
## 6.0.0

* Update default size limit of `CodedBufferReader` from 67,108,864 bytes to
2,147,483,647 bytes, and default recursion limit from 64 to 100.
Expand All @@ -13,6 +13,13 @@
message extension field set is initialized and frozen and initialized but not
frozen. ([#1062])

* **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`.

* Fix `PbList` methods `addAll`, `insertAll`, `replaceRange`, `setAll`,
`setRange` iterating the `Iterable` argument twice. ([#730], [#1070])

Expand Down
12 changes: 6 additions & 6 deletions protobuf/lib/src/protobuf/field_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class FieldInfo<T> {
this.enumValues,
this.defaultEnumValue,
String? protoName,
}) : makeDefault = (() => PbList<T>(check: check)),
}) : makeDefault = (() => newPbList<T>(check: check)),
_protoName = protoName,
assert(PbFieldType.isRepeated(type)),
assert(!PbFieldType.isEnum(type) || valueOf != null);
Expand All @@ -169,7 +169,7 @@ class FieldInfo<T> {
/// [GeneratedMessage.getField], doesn't create a repeated field.
dynamic get readonlyDefault {
if (isRepeated) {
return _emptyList ??= PbList.unmodifiable();
return _emptyList ??= newUnmodifiablePbList();
}
return makeDefault!();
}
Expand Down Expand Up @@ -232,13 +232,13 @@ class FieldInfo<T> {
/// Creates a repeated field.
PbList<T> _createRepeatedField() {
assert(isRepeated);
return PbList<T>(check: check);
return newPbList<T>(check: check);
}

/// Same as above, but allow a tighter typed [PbList] to be created.
PbList<S> _createRepeatedFieldWithType<S extends T>() {
assert(isRepeated);
return PbList<S>(check: check);
return newPbList<S>(check: check);
}

/// Convenience method to thread this FieldInfo's reified type parameter to
Expand Down Expand Up @@ -303,7 +303,7 @@ class MapFieldInfo<K, V> extends FieldInfo<PbMap<K, V>?> {
tagNumber,
index,
type,
defaultOrMaker: () => PbMap<K, V>(keyFieldType, valueFieldType),
defaultOrMaker: () => newPbMap<K, V>(keyFieldType, valueFieldType),
defaultEnumValue: defaultEnumValue,
protoName: protoName,
) {
Expand All @@ -319,7 +319,7 @@ class MapFieldInfo<K, V> extends FieldInfo<PbMap<K, V>?> {

PbMap<K, V> _createMapField() {
assert(isMapField);
return PbMap<K, V>(keyFieldType, valueFieldType);
return newPbMap<K, V>(keyFieldType, valueFieldType);
}
}

Expand Down
2 changes: 1 addition & 1 deletion protobuf/lib/src/protobuf/field_set.dart
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ class FieldSet {
assert(fi.isMapField);

if (_isReadOnly) {
return PbMap<K, V>.unmodifiable(fi.keyFieldType, fi.valueFieldType);
return newUnmodifiablePbMap<K, V>(fi.keyFieldType, fi.valueFieldType);
}

final map = fi._createMapField();
Expand Down
21 changes: 14 additions & 7 deletions protobuf/lib/src/protobuf/pb_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ import 'utils.dart';
/// Throws [ArgumentError] or [RangeError] when the item is not valid.
typedef CheckFunc<E> = void Function(E? x);

@pragma('dart2js:tryInline')
@pragma('vm:prefer-inline')
@pragma('wasm:prefer-inline')
PbList<E> newPbList<E>({CheckFunc<E>? check}) => PbList._(check: check);

@pragma('dart2js:tryInline')
@pragma('vm:prefer-inline')
@pragma('wasm:prefer-inline')
PbList<E> newUnmodifiablePbList<E>({CheckFunc<E>? check}) =>
PbList._unmodifiable();

/// A [ListBase] implementation used for protobuf `repeated` fields.
class PbList<E> extends ListBase<E> {
/// The actual list storing the elements.
Expand All @@ -35,17 +46,13 @@ class PbList<E> extends ListBase<E> {

bool get isFrozen => _isReadOnly;

PbList({CheckFunc<E>? check}) : _wrappedList = <E>[], _check = check;
PbList._({CheckFunc<E>? check}) : _wrappedList = <E>[], _check = check;

PbList.unmodifiable()
PbList._unmodifiable()
: _wrappedList = _emptyList,
_check = checkNotNull,
_isReadOnly = true;

PbList.from(Iterable<E> from)
: _wrappedList = List<E>.of(from),
_check = checkNotNull;

@override
@pragma('dart2js:never-inline')
void add(E element) {
Expand Down Expand Up @@ -288,7 +295,7 @@ class PbList<E> extends ListBase<E> {
}

PbList<E> _deepCopy() {
final newList = PbList<E>(check: _check);
final newList = PbList<E>._(check: _check);
final wrappedList = _wrappedList;
final newWrappedList = newList._wrappedList;
if (wrappedList.isNotEmpty) {
Expand Down
18 changes: 15 additions & 3 deletions protobuf/lib/src/protobuf/pb_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<K, V> newPbMap<K, V>(int keyFieldType, int valueFieldType) =>
PbMap<K, V>._(keyFieldType, valueFieldType);

@pragma('dart2js:tryInline')
@pragma('vm:prefer-inline')
@pragma('wasm:prefer-inline')
PbMap<K, V> newUnmodifiablePbMap<K, V>(int keyFieldType, int valueFieldType) =>
PbMap<K, V>._unmodifiable(keyFieldType, valueFieldType);

/// A [MapBase] implementation used for protobuf `map` fields.
class PbMap<K, V> extends MapBase<K, V> {
/// Key type of the map. Per proto2 and proto3 specs, this needs to be an
Expand All @@ -34,9 +46,9 @@ class PbMap<K, V> extends MapBase<K, V> {

bool _isReadOnly = false;

PbMap(this.keyFieldType, this.valueFieldType) : _wrappedMap = <K, V>{};
PbMap._(this.keyFieldType, this.valueFieldType) : _wrappedMap = <K, V>{};

PbMap.unmodifiable(this.keyFieldType, this.valueFieldType)
PbMap._unmodifiable(this.keyFieldType, this.valueFieldType)
: _wrappedMap = <K, V>{},
_isReadOnly = true;

Expand Down Expand Up @@ -114,7 +126,7 @@ class PbMap<K, V> extends MapBase<K, V> {
}

PbMap<K, V> _deepCopy() {
final newMap = PbMap<K, V>(keyFieldType, valueFieldType);
final newMap = PbMap<K, V>._(keyFieldType, valueFieldType);
final wrappedMap = _wrappedMap;
final newWrappedMap = newMap._wrappedMap;
if (PbFieldType.isGroupOrMessage(valueFieldType)) {
Expand Down
2 changes: 1 addition & 1 deletion protobuf/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: protobuf
version: 5.1.0-wip
version: 6.0.0
description: >-
Runtime library for protocol buffers support. Use with package:protoc_plugin
to generate Dart code for your '.proto' files.
Expand Down
179 changes: 3 additions & 176 deletions protobuf/test/list_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(Object? x) => x as T;
import 'mock_util.dart';

void main() {
test('testPbList handles basic operations', () {
final lb1 = PbList<int>();
final lb1 = T().int32s;
expect(lb1, []);

lb1.add(1);
Expand Down Expand Up @@ -63,7 +54,7 @@ void main() {
});

test('PbList handles range operations', () {
final lb2 = PbList<int>();
final lb2 = T().int32s;

lb2.addAll([1, 2, 3, 4, 5, 6, 7, 8, 9]);
expect(lb2.sublist(3, 7), [4, 5, 6, 7]);
Expand All @@ -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<int>() as List).add('hello');
}, throwsA(TypeMatcher<TypeError>()));
});

test('PbList for signed int32 validates items', () {
final List<int> 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<int> 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<double> 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<Int64> 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<Int64> 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',
);
});
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed because we no longer have access to PbList. We could test these using generated messages (by moving the test to protoc_plugin/test), but we already test the same things in https://github.com/google/protobuf.dart/blob/master/protoc_plugin/test/validate_fail_test.dart so these are also redundant.

}
2 changes: 1 addition & 1 deletion protoc_plugin/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down