1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
|
// Copyright 2022 Harald Albrecht.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package enumflag
import (
"fmt"
"slices"
"sort"
"strings"
)
// EnumIdentifiers maps enumeration values to their corresponding textual
// representations (~identifiers). This mapping is a one-to-many mapping in that
// the same enumeration value may have more than only one associated textual
// representation (identifier). If more than one textual representation exists
// for the same enumeration value, then the first textual representation is
// considered to be the canonical one.
type EnumIdentifiers[E comparable] map[E][]string
// enumMapper is an optionally case insensitive map from enum values to their
// corresponding textual representations.
type enumMapper[E comparable] struct {
m EnumIdentifiers[E]
sensitivity EnumCaseSensitivity
}
// newEnumMapper returns a new enumMapper for the given mapping and case
// sensitivity or insensitivity.
func newEnumMapper[E comparable](mapping EnumIdentifiers[E], sensitivity EnumCaseSensitivity) enumMapper[E] {
return enumMapper[E]{
m: mapping,
sensitivity: sensitivity,
}
}
// Lookup returns the enum textual representations (identifiers) for the
// specified enum value, if any; otherwise, returns a zero string slice.
func (m enumMapper[E]) Lookup(enum E) (names []string) {
return m.m[enum]
}
// ValueOf returns the enumeration value corresponding with the specified
// textual representation (identifier), or an error if no match is found.
func (m enumMapper[E]) ValueOf(name string) (E, error) {
comparefn := func(s string) bool { return s == name }
if m.sensitivity == EnumCaseInsensitive {
name = strings.ToLower(name)
comparefn = func(s string) bool { return strings.ToLower(s) == name }
}
// Try to find a matching enum value textual representation, and then take
// its enumeration value ("code").
for enumval, ids := range m.m {
if slices.IndexFunc(ids, comparefn) >= 0 {
return enumval, nil
}
}
// Oh no! An invalid textual enum value was specified, so let's generate
// some useful error explaining which textual representations are valid.
// We're ordering values by their canonical names in order to achieve a
// stable error message.
allids := []string{}
for _, ids := range m.m {
s := []string{}
for _, id := range ids {
s = append(s, "'"+id+"'")
}
allids = append(allids, strings.Join(s, "/"))
}
sort.Strings(allids)
var zero E
return zero, fmt.Errorf("must be %s", strings.Join(allids, ", "))
}
// Mapping returns the mapping of enum values to their names.
func (m enumMapper[E]) Mapping() EnumIdentifiers[E] {
return m.m
}
|