Skip to content
93 changes: 72 additions & 21 deletions protobuf/lib/src/protobuf/builder_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ class BuilderInfo {
dynamic defaultOrMaker,
CreateBuilderFunc? subBuilder,
ValueOfFunc? valueOf,
bool? sparseEnum,
List<ProtobufEnum>? enumValues,
List<ProtobufEnum?>? enumValuesByTag,
{String? protoName}) {
final index = byIndex.length;
final fieldInfo = (tagNumber == 0)
Expand All @@ -71,7 +73,9 @@ class BuilderInfo {
defaultOrMaker: defaultOrMaker,
subBuilder: subBuilder,
valueOf: valueOf,
sparseEnum: sparseEnum,
enumValues: enumValues,
enumValuesByTag: enumValuesByTag,
protoName: protoName);
_addField(fieldInfo);
}
Expand Down Expand Up @@ -99,13 +103,17 @@ class BuilderInfo {
CreateBuilderFunc? subBuilder,
ValueOfFunc? valueOf,
List<ProtobufEnum>? enumValues,
List<ProtobufEnum?>? enumValuesByTag,
bool? sparseEnum,
{ProtobufEnum? defaultEnumValue,
String? protoName}) {
final index = byIndex.length;
_addField(FieldInfo<T>.repeated(
name, tagNumber, index, fieldType, check, subBuilder,
valueOf: valueOf,
enumValues: enumValues,
enumValuesByTag: enumValuesByTag,
sparseEnum: sparseEnum,
defaultEnumValue: defaultEnumValue,
protoName: protoName));
}
Expand All @@ -127,74 +135,84 @@ class BuilderInfo {
{dynamic defaultOrMaker,
CreateBuilderFunc? subBuilder,
ValueOfFunc? valueOf,
bool? sparseEnum,
List<ProtobufEnum>? enumValues,
List<ProtobufEnum>? enumValuesByTag,
String? protoName}) {
add<T>(tagNumber, name, fieldType, defaultOrMaker, subBuilder, valueOf,
enumValues,
sparseEnum, enumValues, enumValuesByTag,
protoName: protoName);
}

/// Adds PbFieldType.OS String with no default value to reduce generated
/// code size.
void aOS(int tagNumber, String name, {String? protoName}) {
add<String>(tagNumber, name, PbFieldType.OS, null, null, null, null,
add<String>(
tagNumber, name, PbFieldType.OS, null, null, null, null, null, null,
protoName: protoName);
}

/// Adds PbFieldType.PS String with no default value.
void pPS(int tagNumber, String name, {String? protoName}) {
addRepeated<String>(tagNumber, name, PbFieldType.PS,
getCheckFunction(PbFieldType.PS), null, null, null,
getCheckFunction(PbFieldType.PS), null, null, null, null, null,
protoName: protoName);
}

/// Adds PbFieldType.QS String with no default value.
void aQS(int tagNumber, String name, {String? protoName}) {
add<String>(tagNumber, name, PbFieldType.QS, null, null, null, null,
add<String>(
tagNumber, name, PbFieldType.QS, null, null, null, null, null, null,
protoName: protoName);
}

/// Adds Int64 field with Int64.ZERO default.
void aInt64(int tagNumber, String name, {String? protoName}) {
add<Int64>(tagNumber, name, PbFieldType.O6, Int64.ZERO, null, null, null,
null, null,
protoName: protoName);
}

/// Adds a boolean with no default value.
void aOB(int tagNumber, String name, {String? protoName}) {
add<bool>(tagNumber, name, PbFieldType.OB, null, null, null, null,
add<bool>(
tagNumber, name, PbFieldType.OB, null, null, null, null, null, null,
protoName: protoName);
}

// Enum.
void e<T>(int tagNumber, String name, int fieldType,
{dynamic defaultOrMaker,
ValueOfFunc? valueOf,
bool? sparseEnum,
List<ProtobufEnum>? enumValues,
List<ProtobufEnum?>? enumValuesByTag,
String? protoName}) {
add<T>(
tagNumber, name, fieldType, defaultOrMaker, null, valueOf, enumValues,
add<T>(tagNumber, name, fieldType, defaultOrMaker, null, valueOf,
sparseEnum, enumValues, enumValuesByTag,
protoName: protoName);
}

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

// Repeated message, group, or enum.
void pc<T>(int tagNumber, String name, int fieldType,
{CreateBuilderFunc? subBuilder,
ValueOfFunc? valueOf,
bool? sparseEnum,
List<ProtobufEnum>? enumValues,
List<ProtobufEnum?>? enumValuesByTag,
ProtobufEnum? defaultEnumValue,
String? protoName}) {
assert(_isGroupOrMessage(fieldType) || _isEnum(fieldType));
addRepeated<T>(tagNumber, name, fieldType, _checkNotNull, subBuilder,
valueOf, enumValues,
valueOf, enumValues, enumValuesByTag, sparseEnum,
defaultEnumValue: defaultEnumValue, protoName: protoName);
}

Expand All @@ -208,6 +226,8 @@ class BuilderInfo {
subBuilder,
null,
null,
null,
null,
protoName: protoName);
}

Expand All @@ -221,6 +241,8 @@ class BuilderInfo {
subBuilder,
null,
null,
null,
null,
protoName: protoName);
}

Expand All @@ -238,16 +260,27 @@ class BuilderInfo {
required int valueFieldType,
CreateBuilderFunc? valueCreator,
ValueOfFunc? valueOf,
bool? sparseEnum,
List<ProtobufEnum>? enumValues,
List<ProtobufEnum?>? enumValuesByTag,
ProtobufEnum? defaultEnumValue,
PackageName packageName = const PackageName(''),
String? protoName,
dynamic valueDefaultOrMaker}) {
final mapEntryBuilderInfo = BuilderInfo(entryClassName,
package: packageName)
..add(PbMap._keyFieldNumber, 'key', keyFieldType, null, null, null, null)
..add(PbMap._valueFieldNumber, 'value', valueFieldType,
valueDefaultOrMaker, valueCreator, valueOf, enumValues);
final mapEntryBuilderInfo =
BuilderInfo(entryClassName, package: packageName)
..add(PbMap._keyFieldNumber, 'key', keyFieldType, null, null, null,
null, null, null)
..add(
PbMap._valueFieldNumber,
'value',
valueFieldType,
valueDefaultOrMaker,
valueCreator,
valueOf,
sparseEnum,
enumValues,
enumValuesByTag);

addMapField<K, V>(tagNumber, name, keyFieldType, valueFieldType,
mapEntryBuilderInfo, valueCreator,
Expand Down Expand Up @@ -323,13 +356,31 @@ class BuilderInfo {

ProtobufEnum? _decodeEnum(
int tagNumber, ExtensionRegistry? registry, int rawValue) {
final f = valueOfFunc(tagNumber);
if (f != null) {
return f(rawValue);
final fi = fieldInfo[tagNumber];
if (fi == null) {
return _decodeEnumExtension(tagNumber, registry, rawValue);
}

final valuesByTag = fi.enumValuesByTag;
if (valuesByTag == null) {
return _decodeEnumExtension(tagNumber, registry, rawValue);
}

if (fi.sparseEnum) {
return ProtobufEnum.$_binarySearch(valuesByTag, rawValue);
} else {
if (rawValue >= 0 && rawValue < valuesByTag.length) {
return valuesByTag[rawValue];
} else {
return null;
}
}
return registry
?.getExtension(qualifiedMessageName, tagNumber)
?.valueOf
?.call(rawValue);
}

ProtobufEnum? _decodeEnumExtension(
int tagNumber, ExtensionRegistry? registry, int rawValue) =>
registry
?.getExtension(qualifiedMessageName, tagNumber)
?.valueOf
?.call(rawValue);
}
12 changes: 11 additions & 1 deletion protobuf/lib/src/protobuf/extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,32 @@ class Extension<T> extends FieldInfo<T> {
CreateBuilderFunc? subBuilder,
ValueOfFunc? valueOf,
List<ProtobufEnum>? enumValues,
List<ProtobufEnum?>? enumValuesByTag,
bool? sparseEnum,
String? protoName})
: super(name, tagNumber, null, fieldType,
defaultOrMaker: defaultOrMaker,
subBuilder: subBuilder,
valueOf: valueOf,
enumValues: enumValues,
enumValuesByTag: enumValuesByTag,
sparseEnum: sparseEnum,
protoName: protoName);

Extension.repeated(this.extendee, String name, int tagNumber, int fieldType,
{required CheckFunc<T> check,
CreateBuilderFunc? subBuilder,
ValueOfFunc? valueOf,
List<ProtobufEnum>? enumValues,
List<ProtobufEnum?>? enumValuesByTag,
bool? sparseEnum,
String? protoName})
: super.repeated(name, tagNumber, null, fieldType, check, subBuilder,
valueOf: valueOf, enumValues: enumValues, protoName: protoName);
valueOf: valueOf,
enumValues: enumValues,
enumValuesByTag: enumValuesByTag,
sparseEnum: sparseEnum,
protoName: protoName);

@override
int get hashCode => extendee.hashCode * 31 + tagNumber;
Expand Down
28 changes: 25 additions & 3 deletions protobuf/lib/src/protobuf/field_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,14 @@ class FieldInfo<T> {
/// Only available in fields with message type.
final CreateBuilderFunc? subBuilder;

/// List of all enum values.
/// List of all enum values, in the order they appear in the proto definition.
/// (not sorted by enum name or value)
///
/// Only available in enum fields.
final List<ProtobufEnum>? enumValues;

final List<ProtobufEnum?>? enumValuesByTag;

/// Default enum value.
///
/// Only available in enum fields.
Expand All @@ -93,6 +96,14 @@ class FieldInfo<T> {
/// Only available in enum fields.
final ValueOfFunc? valueOf;

/// Tells the binary decoder how to search in the enum list by tag.
///
/// When the enum is "sparse", the decoder binarys earches.
///
/// Otherwise the decoder indexes the list (after a range check) with the enum
/// value on the wire.
final bool sparseEnum;

/// Function to verify items when adding to a repeated field.
///
/// Only available in repeated fields.
Expand All @@ -103,9 +114,12 @@ class FieldInfo<T> {
this.subBuilder,
this.valueOf,
this.enumValues,
this.enumValuesByTag,
bool? sparseEnum,
this.defaultEnumValue,
String? protoName})
: makeDefault = findMakeDefault(type, defaultOrMaker),
sparseEnum = sparseEnum ?? false,
check = null,
_protoName = protoName,
assert(type != 0),
Expand All @@ -122,16 +136,24 @@ class FieldInfo<T> {
type = 0,
makeDefault = null,
valueOf = null,
sparseEnum = false,
check = null,
enumValues = null,
enumValuesByTag = null,
defaultEnumValue = null,
subBuilder = null;

FieldInfo.repeated(this.name, this.tagNumber, this.index, this.type,
CheckFunc<T> this.check, this.subBuilder,
{this.valueOf, this.enumValues, this.defaultEnumValue, String? protoName})
{this.valueOf,
bool? sparseEnum,
this.enumValues,
this.enumValuesByTag,
this.defaultEnumValue,
String? protoName})
: makeDefault = (() => PbList<T>(check: check)),
_protoName = protoName,
sparseEnum = sparseEnum ?? false,
assert(_isRepeated(type)),
assert(!_isEnum(type) || valueOf != null);

Expand Down Expand Up @@ -277,7 +299,7 @@ class MapFieldInfo<K, V> extends FieldInfo<PbMap<K, V>?> {
defaultOrMaker: () => PbMap<K, V>(keyFieldType, valueFieldType),
defaultEnumValue: defaultEnumValue,
protoName: protoName) {
assert(!_isEnum(type) || valueOf != null);
assert(!_isEnum(type) || (valueOf != null && sparseEnum != null));
}

FieldInfo get valueFieldInfo =>
Expand Down
Loading
Loading