diff --git a/protobuf/lib/src/protobuf/builder_info.dart b/protobuf/lib/src/protobuf/builder_info.dart index 1ae34413..375fe0d6 100644 --- a/protobuf/lib/src/protobuf/builder_info.dart +++ b/protobuf/lib/src/protobuf/builder_info.dart @@ -62,7 +62,9 @@ class BuilderInfo { dynamic defaultOrMaker, CreateBuilderFunc? subBuilder, ValueOfFunc? valueOf, + bool? sparseEnum, List? enumValues, + List? enumValuesByTag, {String? protoName}) { final index = byIndex.length; final fieldInfo = (tagNumber == 0) @@ -71,7 +73,9 @@ class BuilderInfo { defaultOrMaker: defaultOrMaker, subBuilder: subBuilder, valueOf: valueOf, + sparseEnum: sparseEnum, enumValues: enumValues, + enumValuesByTag: enumValuesByTag, protoName: protoName); _addField(fieldInfo); } @@ -99,6 +103,8 @@ class BuilderInfo { CreateBuilderFunc? subBuilder, ValueOfFunc? valueOf, List? enumValues, + List? enumValuesByTag, + bool? sparseEnum, {ProtobufEnum? defaultEnumValue, String? protoName}) { final index = byIndex.length; @@ -106,6 +112,8 @@ class BuilderInfo { name, tagNumber, index, fieldType, check, subBuilder, valueOf: valueOf, enumValues: enumValues, + enumValuesByTag: enumValuesByTag, + sparseEnum: sparseEnum, defaultEnumValue: defaultEnumValue, protoName: protoName)); } @@ -127,42 +135,48 @@ class BuilderInfo { {dynamic defaultOrMaker, CreateBuilderFunc? subBuilder, ValueOfFunc? valueOf, + bool? sparseEnum, List? enumValues, + List? enumValuesByTag, String? protoName}) { add(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(tagNumber, name, PbFieldType.OS, null, null, null, null, + add( + 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(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(tagNumber, name, PbFieldType.QS, null, null, null, null, + add( + 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(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(tagNumber, name, PbFieldType.OB, null, null, null, null, + add( + tagNumber, name, PbFieldType.OB, null, null, null, null, null, null, protoName: protoName); } @@ -170,10 +184,12 @@ class BuilderInfo { void e(int tagNumber, String name, int fieldType, {dynamic defaultOrMaker, ValueOfFunc? valueOf, + bool? sparseEnum, List? enumValues, + List? enumValuesByTag, String? protoName}) { - add( - tagNumber, name, fieldType, defaultOrMaker, null, valueOf, enumValues, + add(tagNumber, name, fieldType, defaultOrMaker, null, valueOf, + sparseEnum, enumValues, enumValuesByTag, protoName: protoName); } @@ -181,7 +197,7 @@ class BuilderInfo { void p(int tagNumber, String name, int fieldType, {String? protoName}) { assert(!_isGroupOrMessage(fieldType) && !_isEnum(fieldType)); addRepeated(tagNumber, name, fieldType, getCheckFunction(fieldType), - null, null, null, + null, null, null, null, null, protoName: protoName); } @@ -189,12 +205,14 @@ class BuilderInfo { void pc(int tagNumber, String name, int fieldType, {CreateBuilderFunc? subBuilder, ValueOfFunc? valueOf, + bool? sparseEnum, List? enumValues, + List? enumValuesByTag, ProtobufEnum? defaultEnumValue, String? protoName}) { assert(_isGroupOrMessage(fieldType) || _isEnum(fieldType)); addRepeated(tagNumber, name, fieldType, _checkNotNull, subBuilder, - valueOf, enumValues, + valueOf, enumValues, enumValuesByTag, sparseEnum, defaultEnumValue: defaultEnumValue, protoName: protoName); } @@ -208,6 +226,8 @@ class BuilderInfo { subBuilder, null, null, + null, + null, protoName: protoName); } @@ -221,6 +241,8 @@ class BuilderInfo { subBuilder, null, null, + null, + null, protoName: protoName); } @@ -238,16 +260,27 @@ class BuilderInfo { required int valueFieldType, CreateBuilderFunc? valueCreator, ValueOfFunc? valueOf, + bool? sparseEnum, List? enumValues, + List? 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(tagNumber, name, keyFieldType, valueFieldType, mapEntryBuilderInfo, valueCreator, @@ -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); } diff --git a/protobuf/lib/src/protobuf/extension.dart b/protobuf/lib/src/protobuf/extension.dart index 1144443f..9736d172 100644 --- a/protobuf/lib/src/protobuf/extension.dart +++ b/protobuf/lib/src/protobuf/extension.dart @@ -13,12 +13,16 @@ class Extension extends FieldInfo { CreateBuilderFunc? subBuilder, ValueOfFunc? valueOf, List? enumValues, + List? 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, @@ -26,9 +30,15 @@ class Extension extends FieldInfo { CreateBuilderFunc? subBuilder, ValueOfFunc? valueOf, List? enumValues, + List? 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; diff --git a/protobuf/lib/src/protobuf/field_info.dart b/protobuf/lib/src/protobuf/field_info.dart index 1777e090..db4034d4 100644 --- a/protobuf/lib/src/protobuf/field_info.dart +++ b/protobuf/lib/src/protobuf/field_info.dart @@ -78,11 +78,14 @@ class FieldInfo { /// 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? enumValues; + final List? enumValuesByTag; + /// Default enum value. /// /// Only available in enum fields. @@ -93,6 +96,14 @@ class FieldInfo { /// 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. @@ -103,9 +114,12 @@ class FieldInfo { 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), @@ -122,16 +136,24 @@ class FieldInfo { 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 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(check: check)), _protoName = protoName, + sparseEnum = sparseEnum ?? false, assert(_isRepeated(type)), assert(!_isEnum(type) || valueOf != null); @@ -277,7 +299,7 @@ class MapFieldInfo extends FieldInfo?> { defaultOrMaker: () => PbMap(keyFieldType, valueFieldType), defaultEnumValue: defaultEnumValue, protoName: protoName) { - assert(!_isEnum(type) || valueOf != null); + assert(!_isEnum(type) || (valueOf != null && sparseEnum != null)); } FieldInfo get valueFieldInfo => diff --git a/protobuf/lib/src/protobuf/protobuf_enum.dart b/protobuf/lib/src/protobuf/protobuf_enum.dart index b96c119a..4168be27 100644 --- a/protobuf/lib/src/protobuf/protobuf_enum.dart +++ b/protobuf/lib/src/protobuf/protobuf_enum.dart @@ -2,21 +2,25 @@ // 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. +// ignore_for_file: non_constant_identifier_names + part of '../../protobuf.dart'; /// A base class for all proto enum types. /// -/// All proto `enum` classes inherit from [ProtobufEnum]. For example, given -/// the following enum defined in a proto file: +/// All proto `enum` classes inherit from [ProtobufEnum]. For example, given the +/// following enum defined in a proto file: /// -/// message MyMessage { -/// enum Color { -/// RED = 0; -/// GREEN = 1; -/// BLUE = 2; -/// }; -/// // ... -/// } +/// ``` +/// message MyMessage { +/// enum Color { +/// RED = 0; +/// GREEN = 1; +/// BLUE = 2; +/// }; +/// // ... +/// } +/// ``` /// /// the generated Dart file will include a `MyMessage_Color` class that extends /// `ProtobufEnum`. It will also include a `const MyMessage_Color` for each of @@ -37,16 +41,39 @@ class ProtobufEnum { /// Creates a new constant [ProtobufEnum] using [value] and [name]. const ProtobufEnum(this.value, this.name); - /// Creates a Map for all of the [ProtobufEnum]s in [byIndex], mapping each - /// [ProtobufEnum]'s [value] to the [ProtobufEnum]. - static Map initByValue(List byIndex) { - final byValue = {}; - for (final v in byIndex) { - byValue[v.value] = v; + /// @nodoc + static List $_initDenseList(List byIndex) { + if (byIndex.isEmpty) return []; + final byValue = List.filled(byIndex.last.value + 1, null); + for (final enumValue in byIndex) { + byValue[enumValue.value] = enumValue; } return byValue; } + /// @nodoc + static List $_initSparseList(List byIndex) => + byIndex.toList()..sort((e1, e2) => e1.value.compareTo(e2.value)); + + /// @nodoc + static T? $_binarySearch( + List sortedList, int value) { + var min = 0; + var max = sortedList.length; + while (min < max) { + final mid = min + ((max - min) >> 1); + final element = sortedList[mid]; + final comp = element!.value.compareTo(value); + if (comp == 0) return element; + if (comp < 0) { + min = mid + 1; + } else { + max = mid; + } + } + return null; + } + /// Returns this enum's [name] or the [value] if names are not represented. @override String toString() => name == '' ? value.toString() : name; diff --git a/protoc_plugin/lib/protoc.dart b/protoc_plugin/lib/protoc.dart index e6d175bd..2ce0dd0a 100644 --- a/protoc_plugin/lib/protoc.dart +++ b/protoc_plugin/lib/protoc.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:collection/collection.dart'; import 'package:protobuf/protobuf.dart'; import 'const_generator.dart' show writeJsonConst; diff --git a/protoc_plugin/lib/src/enum_generator.dart b/protoc_plugin/lib/src/enum_generator.dart index a1cd8b5f..8fb72eb3 100644 --- a/protoc_plugin/lib/src/enum_generator.dart +++ b/protoc_plugin/lib/src/enum_generator.dart @@ -102,6 +102,9 @@ class EnumGenerator extends ProtobufContainer { static const int _enumValueTag = 2; void generate(IndentingWriter out) { + assert(_canonicalValues + .isSortedBy((EnumValueDescriptorProto a) => a.number)); + final commentBlock = fileGen?.commentBlock(fieldPath); if (commentBlock != null) { out.println(commentBlock); @@ -165,7 +168,6 @@ class EnumGenerator extends ProtobufContainer { } } out.println(); - out.println('static const $coreImportPrefix.List<$classname> values =' ' <$classname> ['); for (final val in _canonicalValues) { @@ -175,11 +177,38 @@ class EnumGenerator extends ProtobufContainer { out.println('];'); out.println(); - out.println( - 'static final $coreImportPrefix.Map<$coreImportPrefix.int, $classname> _byValue =' - ' $protobufImportPrefix.ProtobufEnum.initByValue(values);'); - out.println('static $classname? valueOf($coreImportPrefix.int value) =>' - ' _byValue[value];'); + var useList = _canonicalValues.isEmpty; + if (_canonicalValues.isNotEmpty) { + if (_canonicalValues.every((val) => !val.number.isNegative)) { + if (_canonicalValues.length / (_canonicalValues.last.number + 1) >= + 0.7) { + useList = true; + } + } + } + + if (useList) { + out.println( + 'static final $coreImportPrefix.List<$classname?> enumValuesByTag =' + ' $protobufImportPrefix.ProtobufEnum.\$_initDenseList(values);'); + + out.println( + 'static final $coreImportPrefix.bool \$_sparseEnum = false;'); + + out.println('static $classname? valueOf($coreImportPrefix.int value) =>' + ' value < 0 || value >= enumValuesByTag.length ? null : enumValuesByTag[value];'); + } else { + out.println( + 'static final $coreImportPrefix.List<$classname> enumValuesByTag =' + ' $protobufImportPrefix.ProtobufEnum.\$_initSparseList(values);'); + + out.println( + 'static final $coreImportPrefix.bool \$_sparseEnum = true;'); + + out.println('static $classname? valueOf($coreImportPrefix.int value) =>' + ' $protobufImportPrefix.ProtobufEnum.\$_binarySearch(enumValuesByTag, value);'); + } + out.println(); out.println('const $classname._(super.v, super.n);'); diff --git a/protoc_plugin/lib/src/extension_generator.dart b/protoc_plugin/lib/src/extension_generator.dart index f9eef30f..bf7a5568 100644 --- a/protoc_plugin/lib/src/extension_generator.dart +++ b/protoc_plugin/lib/src/extension_generator.dart @@ -121,6 +121,8 @@ class ExtensionGenerator { } else if (type.isEnum) { named['valueOf'] = '$dartType.valueOf'; named['enumValues'] = '$dartType.values'; + named['enumValuesByTag'] = '$dartType.enumValuesByTag'; + named['sparseEnum'] = '$dartType.\$_sparseEnum'; } } else { invocation = '$protobufImportPrefix.Extension<$dartType>'; @@ -131,6 +133,8 @@ class ExtensionGenerator { final dartEnum = type.getDartType(fileGen!); named['valueOf'] = '$dartEnum.valueOf'; named['enumValues'] = '$dartEnum.values'; + named['enumValuesByTag'] = '$dartEnum.enumValuesByTag'; + named['sparseEnum'] = '$dartEnum.\$_sparseEnum'; } } final fieldDefinition = 'static final '; diff --git a/protoc_plugin/lib/src/generated/descriptor.pb.dart b/protoc_plugin/lib/src/generated/descriptor.pb.dart index a4dfd4cb..32b5a596 100644 --- a/protoc_plugin/lib/src/generated/descriptor.pb.dart +++ b/protoc_plugin/lib/src/generated/descriptor.pb.dart @@ -768,12 +768,16 @@ class FieldDescriptorProto extends $pb.GeneratedMessage { 4, _omitFieldNames ? '' : 'label', $pb.PbFieldType.OE, defaultOrMaker: FieldDescriptorProto_Label.LABEL_OPTIONAL, valueOf: FieldDescriptorProto_Label.valueOf, - enumValues: FieldDescriptorProto_Label.values) + enumValues: FieldDescriptorProto_Label.values, + enumValuesByTag: FieldDescriptorProto_Label.enumValuesByTag, + sparseEnum: FieldDescriptorProto_Label.$_sparseEnum) ..e( 5, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OE, defaultOrMaker: FieldDescriptorProto_Type.TYPE_DOUBLE, valueOf: FieldDescriptorProto_Type.valueOf, - enumValues: FieldDescriptorProto_Type.values) + enumValues: FieldDescriptorProto_Type.values, + enumValuesByTag: FieldDescriptorProto_Type.enumValuesByTag, + sparseEnum: FieldDescriptorProto_Type.$_sparseEnum) ..aOS(6, _omitFieldNames ? '' : 'typeName') ..aOS(7, _omitFieldNames ? '' : 'defaultValue') ..aOM(8, _omitFieldNames ? '' : 'options', @@ -1734,7 +1738,9 @@ class FileOptions extends $pb.GeneratedMessage { 9, _omitFieldNames ? '' : 'optimizeFor', $pb.PbFieldType.OE, defaultOrMaker: FileOptions_OptimizeMode.SPEED, valueOf: FileOptions_OptimizeMode.valueOf, - enumValues: FileOptions_OptimizeMode.values) + enumValues: FileOptions_OptimizeMode.values, + enumValuesByTag: FileOptions_OptimizeMode.enumValuesByTag, + sparseEnum: FileOptions_OptimizeMode.$_sparseEnum) ..aOB(10, _omitFieldNames ? '' : 'javaMultipleFiles') ..aOS(11, _omitFieldNames ? '' : 'goPackage') ..aOB(16, _omitFieldNames ? '' : 'ccGenericServices') @@ -2313,7 +2319,9 @@ class FieldOptions extends $pb.GeneratedMessage { 1, _omitFieldNames ? '' : 'ctype', $pb.PbFieldType.OE, defaultOrMaker: FieldOptions_CType.STRING, valueOf: FieldOptions_CType.valueOf, - enumValues: FieldOptions_CType.values) + enumValues: FieldOptions_CType.values, + enumValuesByTag: FieldOptions_CType.enumValuesByTag, + sparseEnum: FieldOptions_CType.$_sparseEnum) ..aOB(2, _omitFieldNames ? '' : 'packed') ..aOB(3, _omitFieldNames ? '' : 'deprecated') ..aOB(5, _omitFieldNames ? '' : 'lazy') @@ -2321,7 +2329,9 @@ class FieldOptions extends $pb.GeneratedMessage { 6, _omitFieldNames ? '' : 'jstype', $pb.PbFieldType.OE, defaultOrMaker: FieldOptions_JSType.JS_NORMAL, valueOf: FieldOptions_JSType.valueOf, - enumValues: FieldOptions_JSType.values) + enumValues: FieldOptions_JSType.values, + enumValuesByTag: FieldOptions_JSType.enumValuesByTag, + sparseEnum: FieldOptions_JSType.$_sparseEnum) ..aOB(10, _omitFieldNames ? '' : 'weak') ..pc( 999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM, @@ -2822,7 +2832,9 @@ class MethodOptions extends $pb.GeneratedMessage { 34, _omitFieldNames ? '' : 'idempotencyLevel', $pb.PbFieldType.OE, defaultOrMaker: MethodOptions_IdempotencyLevel.IDEMPOTENCY_UNKNOWN, valueOf: MethodOptions_IdempotencyLevel.valueOf, - enumValues: MethodOptions_IdempotencyLevel.values) + enumValues: MethodOptions_IdempotencyLevel.values, + enumValuesByTag: MethodOptions_IdempotencyLevel.enumValuesByTag, + sparseEnum: MethodOptions_IdempotencyLevel.$_sparseEnum) ..pc( 999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM, subBuilder: UninterpretedOption.create) diff --git a/protoc_plugin/lib/src/generated/descriptor.pbenum.dart b/protoc_plugin/lib/src/generated/descriptor.pbenum.dart index dc6f349d..bc63a97d 100644 --- a/protoc_plugin/lib/src/generated/descriptor.pbenum.dart +++ b/protoc_plugin/lib/src/generated/descriptor.pbenum.dart @@ -88,9 +88,13 @@ class FieldDescriptorProto_Type extends $pb.ProtobufEnum { TYPE_SINT64, ]; - static final $core.Map<$core.int, FieldDescriptorProto_Type> _byValue = - $pb.ProtobufEnum.initByValue(values); - static FieldDescriptorProto_Type? valueOf($core.int value) => _byValue[value]; + static final $core.List enumValuesByTag = + $pb.ProtobufEnum.$_initDenseList(values); + static final $core.bool $_sparseEnum = false; + static FieldDescriptorProto_Type? valueOf($core.int value) => + value < 0 || value >= enumValuesByTag.length + ? null + : enumValuesByTag[value]; const FieldDescriptorProto_Type._(super.v, super.n); } @@ -111,10 +115,13 @@ class FieldDescriptorProto_Label extends $pb.ProtobufEnum { LABEL_REPEATED, ]; - static final $core.Map<$core.int, FieldDescriptorProto_Label> _byValue = - $pb.ProtobufEnum.initByValue(values); + static final $core.List enumValuesByTag = + $pb.ProtobufEnum.$_initDenseList(values); + static final $core.bool $_sparseEnum = false; static FieldDescriptorProto_Label? valueOf($core.int value) => - _byValue[value]; + value < 0 || value >= enumValuesByTag.length + ? null + : enumValuesByTag[value]; const FieldDescriptorProto_Label._(super.v, super.n); } @@ -137,9 +144,13 @@ class FileOptions_OptimizeMode extends $pb.ProtobufEnum { LITE_RUNTIME, ]; - static final $core.Map<$core.int, FileOptions_OptimizeMode> _byValue = - $pb.ProtobufEnum.initByValue(values); - static FileOptions_OptimizeMode? valueOf($core.int value) => _byValue[value]; + static final $core.List enumValuesByTag = + $pb.ProtobufEnum.$_initDenseList(values); + static final $core.bool $_sparseEnum = false; + static FileOptions_OptimizeMode? valueOf($core.int value) => + value < 0 || value >= enumValuesByTag.length + ? null + : enumValuesByTag[value]; const FileOptions_OptimizeMode._(super.v, super.n); } @@ -159,9 +170,13 @@ class FieldOptions_CType extends $pb.ProtobufEnum { STRING_PIECE, ]; - static final $core.Map<$core.int, FieldOptions_CType> _byValue = - $pb.ProtobufEnum.initByValue(values); - static FieldOptions_CType? valueOf($core.int value) => _byValue[value]; + static final $core.List enumValuesByTag = + $pb.ProtobufEnum.$_initDenseList(values); + static final $core.bool $_sparseEnum = false; + static FieldOptions_CType? valueOf($core.int value) => + value < 0 || value >= enumValuesByTag.length + ? null + : enumValuesByTag[value]; const FieldOptions_CType._(super.v, super.n); } @@ -185,9 +200,13 @@ class FieldOptions_JSType extends $pb.ProtobufEnum { JS_NUMBER, ]; - static final $core.Map<$core.int, FieldOptions_JSType> _byValue = - $pb.ProtobufEnum.initByValue(values); - static FieldOptions_JSType? valueOf($core.int value) => _byValue[value]; + static final $core.List enumValuesByTag = + $pb.ProtobufEnum.$_initDenseList(values); + static final $core.bool $_sparseEnum = false; + static FieldOptions_JSType? valueOf($core.int value) => + value < 0 || value >= enumValuesByTag.length + ? null + : enumValuesByTag[value]; const FieldOptions_JSType._(super.v, super.n); } @@ -212,10 +231,13 @@ class MethodOptions_IdempotencyLevel extends $pb.ProtobufEnum { IDEMPOTENT, ]; - static final $core.Map<$core.int, MethodOptions_IdempotencyLevel> _byValue = - $pb.ProtobufEnum.initByValue(values); + static final $core.List enumValuesByTag = + $pb.ProtobufEnum.$_initDenseList(values); + static final $core.bool $_sparseEnum = false; static MethodOptions_IdempotencyLevel? valueOf($core.int value) => - _byValue[value]; + value < 0 || value >= enumValuesByTag.length + ? null + : enumValuesByTag[value]; const MethodOptions_IdempotencyLevel._(super.v, super.n); } diff --git a/protoc_plugin/lib/src/generated/plugin.pbenum.dart b/protoc_plugin/lib/src/generated/plugin.pbenum.dart index 399158c5..b145b453 100644 --- a/protoc_plugin/lib/src/generated/plugin.pbenum.dart +++ b/protoc_plugin/lib/src/generated/plugin.pbenum.dart @@ -27,10 +27,13 @@ class CodeGeneratorResponse_Feature extends $pb.ProtobufEnum { FEATURE_PROTO3_OPTIONAL, ]; - static final $core.Map<$core.int, CodeGeneratorResponse_Feature> _byValue = - $pb.ProtobufEnum.initByValue(values); + static final $core.List enumValuesByTag = + $pb.ProtobufEnum.$_initDenseList(values); + static final $core.bool $_sparseEnum = false; static CodeGeneratorResponse_Feature? valueOf($core.int value) => - _byValue[value]; + value < 0 || value >= enumValuesByTag.length + ? null + : enumValuesByTag[value]; const CodeGeneratorResponse_Feature._(super.v, super.n); } diff --git a/protoc_plugin/lib/src/protobuf_field.dart b/protoc_plugin/lib/src/protobuf_field.dart index 7906cbec..6d14bd05 100644 --- a/protoc_plugin/lib/src/protobuf_field.dart +++ b/protoc_plugin/lib/src/protobuf_field.dart @@ -240,6 +240,8 @@ class ProtobufField { if (value.baseType.isEnum) { named['valueOf'] = '$valueType.valueOf'; named['enumValues'] = '$valueType.values'; + named['enumValuesByTag'] = '$valueType.enumValuesByTag'; + named['sparseEnum'] = '$valueType.\$_sparseEnum'; named['valueDefaultOrMaker'] = value.generateDefaultFunction(); named['defaultEnumValue'] = value.generateDefaultFunction(); } @@ -263,6 +265,8 @@ class ProtobufField { } else if (baseType.isEnum) { named['valueOf'] = '$type.valueOf'; named['enumValues'] = '$type.values'; + named['enumValuesByTag'] = '$type.enumValuesByTag'; + named['sparseEnum'] = '$type.\$_sparseEnum'; named['defaultEnumValue'] = generateDefaultFunction(); } } @@ -275,6 +279,8 @@ class ProtobufField { named['defaultOrMaker'] = makeDefault; named['valueOf'] = '$type.valueOf'; named['enumValues'] = '$type.values'; + named['enumValuesByTag'] = '$type.enumValuesByTag'; + named['sparseEnum'] = '$type.\$_sparseEnum'; invocation = 'e<$type>'; } else if (makeDefault == null) { switch (type) { diff --git a/protoc_plugin/test/goldens/deprecations.pbenum b/protoc_plugin/test/goldens/deprecations.pbenum index 30bc5d78..ece62ac4 100644 --- a/protoc_plugin/test/goldens/deprecations.pbenum +++ b/protoc_plugin/test/goldens/deprecations.pbenum @@ -24,9 +24,13 @@ class A extends $pb.ProtobufEnum { A2, ]; - static final $core.Map<$core.int, A> _byValue = - $pb.ProtobufEnum.initByValue(values); - static A? valueOf($core.int value) => _byValue[value]; + static final $core.List enumValuesByTag = + $pb.ProtobufEnum.$_initDenseList(values); + static final $core.bool $_sparseEnum = false; + static A? valueOf($core.int value) => + value < 0 || value >= enumValuesByTag.length + ? null + : enumValuesByTag[value]; const A._(super.v, super.n); } diff --git a/protoc_plugin/test/goldens/doc_comments.pbenum b/protoc_plugin/test/goldens/doc_comments.pbenum index 7cde50e1..8ea773f1 100644 --- a/protoc_plugin/test/goldens/doc_comments.pbenum +++ b/protoc_plugin/test/goldens/doc_comments.pbenum @@ -26,9 +26,13 @@ class A extends $pb.ProtobufEnum { A2, ]; - static final $core.Map<$core.int, A> _byValue = - $pb.ProtobufEnum.initByValue(values); - static A? valueOf($core.int value) => _byValue[value]; + static final $core.List enumValuesByTag = + $pb.ProtobufEnum.$_initDenseList(values); + static final $core.bool $_sparseEnum = false; + static A? valueOf($core.int value) => + value < 0 || value >= enumValuesByTag.length + ? null + : enumValuesByTag[value]; const A._(super.v, super.n); } diff --git a/protoc_plugin/test/goldens/enum b/protoc_plugin/test/goldens/enum index 812247dd..9a659088 100644 --- a/protoc_plugin/test/goldens/enum +++ b/protoc_plugin/test/goldens/enum @@ -11,8 +11,9 @@ class PhoneType extends $pb.ProtobufEnum { WORK, ]; - static final $core.Map<$core.int, PhoneType> _byValue = $pb.ProtobufEnum.initByValue(values); - static PhoneType? valueOf($core.int value) => _byValue[value]; + static final $core.List enumValuesByTag = $pb.ProtobufEnum.$_initDenseList(values); + static final $core.bool $_sparseEnum = false; + static PhoneType? valueOf($core.int value) => value < 0 || value >= enumValuesByTag.length ? null : enumValuesByTag[value]; const PhoneType._(super.v, super.n); } diff --git a/protoc_plugin/test/goldens/messageGenerator b/protoc_plugin/test/goldens/messageGenerator index 5eab0203..7e337042 100644 --- a/protoc_plugin/test/goldens/messageGenerator +++ b/protoc_plugin/test/goldens/messageGenerator @@ -6,7 +6,7 @@ class PhoneNumber extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PhoneNumber', createEmptyInstance: create) ..aQS(1, _omitFieldNames ? '' : 'number') - ..e(2, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OE, defaultOrMaker: PhoneNumber_PhoneType.MOBILE, valueOf: PhoneNumber_PhoneType.valueOf, enumValues: PhoneNumber_PhoneType.values) + ..e(2, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OE, defaultOrMaker: PhoneNumber_PhoneType.MOBILE, valueOf: PhoneNumber_PhoneType.valueOf, enumValues: PhoneNumber_PhoneType.values, enumValuesByTag: PhoneNumber_PhoneType.enumValuesByTag, sparseEnum: PhoneNumber_PhoneType.$_sparseEnum) ..a<$core.String>(3, _omitFieldNames ? '' : 'name', $pb.PbFieldType.OS, defaultOrMaker: '\$') ..aOS(4, _omitFieldNames ? '' : 'deprecatedField') ; diff --git a/protoc_plugin/test/goldens/messageGenerator.meta b/protoc_plugin/test/goldens/messageGenerator.meta index c398f603..f8e38f2a 100644 --- a/protoc_plugin/test/goldens/messageGenerator.meta +++ b/protoc_plugin/test/goldens/messageGenerator.meta @@ -18,8 +18,8 @@ annotation: { path: 2 path: 1 sourceFile: - begin: 2003 - end: 2009 + begin: 2107 + end: 2113 } annotation: { path: 4 @@ -27,8 +27,8 @@ annotation: { path: 2 path: 1 sourceFile: - begin: 2051 - end: 2057 + begin: 2155 + end: 2161 } annotation: { path: 4 @@ -36,8 +36,8 @@ annotation: { path: 2 path: 1 sourceFile: - begin: 2130 - end: 2139 + begin: 2234 + end: 2243 } annotation: { path: 4 @@ -45,8 +45,8 @@ annotation: { path: 2 path: 1 sourceFile: - begin: 2182 - end: 2193 + begin: 2286 + end: 2297 } annotation: { path: 4 @@ -54,8 +54,8 @@ annotation: { path: 2 path: 0 sourceFile: - begin: 2265 - end: 2269 + begin: 2369 + end: 2373 } annotation: { path: 4 @@ -63,8 +63,8 @@ annotation: { path: 2 path: 0 sourceFile: - begin: 2310 - end: 2314 + begin: 2414 + end: 2418 } annotation: { path: 4 @@ -72,8 +72,8 @@ annotation: { path: 2 path: 0 sourceFile: - begin: 2395 - end: 2402 + begin: 2499 + end: 2506 } annotation: { path: 4 @@ -81,8 +81,8 @@ annotation: { path: 2 path: 0 sourceFile: - begin: 2445 - end: 2454 + begin: 2549 + end: 2558 } annotation: { path: 4 @@ -90,8 +90,8 @@ annotation: { path: 2 path: 2 sourceFile: - begin: 2517 - end: 2521 + begin: 2621 + end: 2625 } annotation: { path: 4 @@ -99,8 +99,8 @@ annotation: { path: 2 path: 2 sourceFile: - begin: 2568 - end: 2572 + begin: 2672 + end: 2676 } annotation: { path: 4 @@ -108,8 +108,8 @@ annotation: { path: 2 path: 2 sourceFile: - begin: 2645 - end: 2652 + begin: 2749 + end: 2756 } annotation: { path: 4 @@ -117,8 +117,8 @@ annotation: { path: 2 path: 2 sourceFile: - begin: 2695 - end: 2704 + begin: 2799 + end: 2808 } annotation: { path: 4 @@ -126,8 +126,8 @@ annotation: { path: 2 path: 3 sourceFile: - begin: 2816 - end: 2831 + begin: 2920 + end: 2935 } annotation: { path: 4 @@ -135,8 +135,8 @@ annotation: { path: 2 path: 3 sourceFile: - begin: 2922 - end: 2937 + begin: 3026 + end: 3041 } annotation: { path: 4 @@ -144,8 +144,8 @@ annotation: { path: 2 path: 3 sourceFile: - begin: 3059 - end: 3077 + begin: 3163 + end: 3181 } annotation: { path: 4 @@ -153,6 +153,6 @@ annotation: { path: 2 path: 3 sourceFile: - begin: 3169 - end: 3189 + begin: 3273 + end: 3293 } diff --git a/protoc_plugin/test/goldens/messageGeneratorEnums b/protoc_plugin/test/goldens/messageGeneratorEnums index 3469c7ba..b6dbeffd 100644 --- a/protoc_plugin/test/goldens/messageGeneratorEnums +++ b/protoc_plugin/test/goldens/messageGeneratorEnums @@ -11,8 +11,9 @@ class PhoneNumber_PhoneType extends $pb.ProtobufEnum { WORK, ]; - static final $core.Map<$core.int, PhoneNumber_PhoneType> _byValue = $pb.ProtobufEnum.initByValue(values); - static PhoneNumber_PhoneType? valueOf($core.int value) => _byValue[value]; + static final $core.List enumValuesByTag = $pb.ProtobufEnum.$_initDenseList(values); + static final $core.bool $_sparseEnum = false; + static PhoneNumber_PhoneType? valueOf($core.int value) => value < 0 || value >= enumValuesByTag.length ? null : enumValuesByTag[value]; const PhoneNumber_PhoneType._(super.v, super.n); } diff --git a/protoc_plugin/test/goldens/topLevelEnum.pbenum b/protoc_plugin/test/goldens/topLevelEnum.pbenum index 30d81a24..8deb35d5 100644 --- a/protoc_plugin/test/goldens/topLevelEnum.pbenum +++ b/protoc_plugin/test/goldens/topLevelEnum.pbenum @@ -26,8 +26,9 @@ class PhoneType extends $pb.ProtobufEnum { WORK, ]; - static final $core.Map<$core.int, PhoneType> _byValue = $pb.ProtobufEnum.initByValue(values); - static PhoneType? valueOf($core.int value) => _byValue[value]; + static final $core.List enumValuesByTag = $pb.ProtobufEnum.$_initDenseList(values); + static final $core.bool $_sparseEnum = false; + static PhoneType? valueOf($core.int value) => value < 0 || value >= enumValuesByTag.length ? null : enumValuesByTag[value]; const PhoneType._(super.v, super.n); }