Skip to content
59 changes: 43 additions & 16 deletions protobuf/lib/src/protobuf/protobuf_enum.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<int, T> initByValue<T extends ProtobufEnum>(List<T> byIndex) {
final byValue = <int, T>{};
for (final v in byIndex) {
byValue[v.value] = v;
/// @nodoc
static List<T?> $_initDenseList<T extends ProtobufEnum>(List<T> byIndex) {
if (byIndex.isEmpty) return [];
final byValue = List<T?>.filled(byIndex.last.value + 1, null);
for (final enumValue in byIndex) {
byValue[enumValue.value] = enumValue;
}
return byValue;
}

/// @nodoc
static List<T> $_initSparseList<T extends ProtobufEnum>(List<T> byIndex) =>
byIndex.toList()..sort((e1, e2) => e1.value.compareTo(e2.value));

/// @nodoc
static T? $_binarySearch<T extends ProtobufEnum>(
List<T> 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;
Expand Down
1 change: 1 addition & 0 deletions protoc_plugin/lib/protoc.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:convert';

import 'package:collection/collection.dart';
import 'package:protobuf/protobuf.dart';

import 'const_generator.dart' show writeJsonConst;
Expand Down
31 changes: 25 additions & 6 deletions protoc_plugin/lib/src/enum_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ class EnumGenerator extends ProtobufContainer {
}
}
out.println();

out.println('static const $coreImportPrefix.List<$classname> values ='
' <$classname> [');
for (final val in _canonicalValues) {
Expand All @@ -175,11 +174,31 @@ 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?> _byValue ='
' $protobufImportPrefix.ProtobufEnum.\$_initDenseList(values);');

out.println('static $classname? valueOf($coreImportPrefix.int value) =>'
' value < 0 || value >= _byValue.length ? null : _byValue[value];');
} else {
out.println('static final $coreImportPrefix.List<$classname> _byValue ='
' $protobufImportPrefix.ProtobufEnum.\$_initSparseList(values);');

out.println('static $classname? valueOf($coreImportPrefix.int value) =>'
' $protobufImportPrefix.ProtobufEnum.\$_binarySearch(_byValue, value);');
}

out.println();

out.println('const $classname._(super.v, super.n);');
Expand Down
40 changes: 22 additions & 18 deletions protoc_plugin/lib/src/generated/descriptor.pbenum.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions protoc_plugin/lib/src/generated/plugin.pbenum.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions protoc_plugin/test/goldens/deprecations.pbenum
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ 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<A?> _byValue =
$pb.ProtobufEnum.$_initDenseList(values);
static A? valueOf($core.int value) =>
value < 0 || value >= _byValue.length ? null : _byValue[value];

const A._(super.v, super.n);
}
Expand Down
7 changes: 4 additions & 3 deletions protoc_plugin/test/goldens/doc_comments.pbenum
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ 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<A?> _byValue =
$pb.ProtobufEnum.$_initDenseList(values);
static A? valueOf($core.int value) =>
value < 0 || value >= _byValue.length ? null : _byValue[value];

const A._(super.v, super.n);
}
Expand Down
4 changes: 2 additions & 2 deletions protoc_plugin/test/goldens/enum
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ 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<PhoneType?> _byValue = $pb.ProtobufEnum.$_initDenseList(values);
static PhoneType? valueOf($core.int value) => value < 0 || value >= _byValue.length ? null : _byValue[value];

const PhoneType._(super.v, super.n);
}
Expand Down
4 changes: 2 additions & 2 deletions protoc_plugin/test/goldens/messageGeneratorEnums
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ 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<PhoneNumber_PhoneType?> _byValue = $pb.ProtobufEnum.$_initDenseList(values);
static PhoneNumber_PhoneType? valueOf($core.int value) => value < 0 || value >= _byValue.length ? null : _byValue[value];

const PhoneNumber_PhoneType._(super.v, super.n);
}
Expand Down
4 changes: 2 additions & 2 deletions protoc_plugin/test/goldens/topLevelEnum.pbenum
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ 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<PhoneType?> _byValue = $pb.ProtobufEnum.$_initDenseList(values);
static PhoneType? valueOf($core.int value) => value < 0 || value >= _byValue.length ? null : _byValue[value];

const PhoneType._(super.v, super.n);
}
Expand Down
Loading