// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file // 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. part of "dart:core"; /// An enumerated value. /// /// This class is implemented by all types and values /// introduced using an `enum` declaration. /// Non-platform classes cannot extend or mix in this class. /// Concrete classes cannot implement the interface. /// /// The identifier used to name an `enum` value is available as a [String], /// via the [EnumName.name] extension property on the `enum` value. @Since("2.14") abstract interface class Enum { /// A numeric identifier for the enumerated value. /// /// The values of a single enumeration are numbered /// consecutively from zero to one less than the /// number of values. /// This is also the index of the value in the /// enumerated type's static `values` list. int get index; /// The value's "name". /// /// The name of a value is a string containing the /// source identifier used to declare the value. /// /// The name occurs in the [toString] of the /// enum value, after the enum class name and a `.`. /// It is exposed by then [EnumName.name] extension getter, /// which is an extension to allow `enum` declarations to have /// an element named `name` without causing a name conflict. /// /// Given an enum declaration like /// ```dart /// enum MyEnum { /// value1, /// value2 /// } /// ``` /// the `toString` method of that class may be implemented /// as /// ```dart /// String toString() => "MyEnum.$_name"; /// ``` String get _name; /// Compares two enum values by their [index]. /// /// A generic [Comparator] function for enum types which /// orders enum values by their [index] value, which corresponds /// to the source order of the enum element declarations in /// the `enum` declaration. /// /// Example: /// ```dart /// enum Season { spring, summer, autumn, winter } /// /// void main() { /// var relationByIndex = /// Enum.compareByIndex(Season.spring, Season.summer); // < 0 /// relationByIndex = /// Enum.compareByIndex(Season.summer, Season.spring); // > 0 /// relationByIndex = /// Enum.compareByIndex(Season.spring, Season.winter); // < 0 /// relationByIndex = /// Enum.compareByIndex(Season.winter, Season.spring); // > 0 /// } /// ``` @Since("2.15") static int compareByIndex(T value1, T value2) => value1.index - value2.index; /// Compares enum values by name. /// /// The [EnumName.name] of an enum value is a string /// representing the source name used to declare that enum value. /// /// This [Comparator] compares two enum values by comparing their names, /// and can be used to sort enum values by their names. /// The comparison uses [String.compareTo], and is therefore case sensitive. /// /// Example: /// ```dart /// enum Season { spring, summer, autumn, winter } /// /// void main() { /// var seasons = [...Season.values]..sort(Enum.compareByName); /// print(seasons); /// // [Season.autumn, Season.spring, Season.summer, Season.winter] /// } /// ``` @Since("2.15") static int compareByName(T value1, T value2) => value1.name.compareTo(value2.name); } /// Superclass of all enum class implementations. @pragma('dyn-module:language-impl:extendable') @pragma('dyn-module:language-impl:callable') abstract class _Enum implements Enum { // See http://dartbug.com/51657 for discussion of dart2js pragma. @pragma('dart2js:noElision') final int index; @pragma('dyn-module:language-impl:callable') final String _name; @pragma('dyn-module:language-impl:callable') const _Enum(this.index, this._name); /// The result of [toString]. /// /// Each enum class can override this method to provide the /// string returned by toString, rather than overriding toString itself. @Since("2.19") @pragma('dyn-module:language-impl:can-be-overridden') String _enumToString(); @override @pragma('dyn-module:language-impl:can-be-overridden') String toString() => _enumToString(); } /// Access to the name of an enum value. /// /// This method is declared as an extension method /// instead of an instance method in order to allow /// enum values to have the name `name`. @Since("2.15") extension EnumName on Enum { /// The name of the enum value. /// /// The name is a string containing the source identifier used /// to declare the enum value. /// /// For example, given a declaration like: /// ```dart /// enum MyEnum { /// value1, /// value2 /// } /// ``` /// the result of `MyEnum.value1.name` is the string `"value1"`. String get name => _name; } /// Access enum values by name. /// /// Extensions on a collection of enum values, /// intended for use on the `values` list of an enum type, /// which allows looking up a value by its name. /// /// Since enum classes are expected to be relatively small, /// lookup of [byName] is performed by linearly iterating through the values /// and comparing their name to the provided name. /// If a more efficient lookup is needed, perhaps because the lookup operation /// happens very often, consider building a map instead using [asNameMap]: /// ```dart /// static myEnumNameMap = MyEnum.values.asNameMap(); /// ``` /// and then use that for lookups. @Since("2.15") extension EnumByName on Iterable { /// Finds the enum value in this list with name [name]. /// /// Goes through this collection looking for an enum with /// name [name], as reported by [EnumName.name]. /// Returns the first value with the given name. Such a value must be found. T byName(String name) { for (var value in this) { if (value._name == name) return value; } throw ArgumentError.value(name, "name", "No enum value with that name"); } /// Creates a map from the names of enum values to the values. /// /// The collection that this method is called on is expected to have /// enums with distinct names, like the `values` list of an enum class. /// Only one value for each name can occur in the created map, /// so if two or more enum values have the same name (either being the /// same value, or being values of different enum type), at most one of /// them will be represented in the returned map. Map asNameMap() => { for (var value in this) value._name: value, }; }