github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/settings/enum.go (about) 1 // Copyright 2017 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package settings 12 13 import ( 14 "bytes" 15 "fmt" 16 "sort" 17 "strconv" 18 "strings" 19 20 "github.com/cockroachdb/errors" 21 ) 22 23 // EnumSetting is a StringSetting that restricts the values to be one of the `enumValues` 24 type EnumSetting struct { 25 IntSetting 26 enumValues map[int64]string 27 } 28 29 var _ extendedSetting = &EnumSetting{} 30 31 // Typ returns the short (1 char) string denoting the type of setting. 32 func (e *EnumSetting) Typ() string { 33 return "e" 34 } 35 36 // String returns the enum's string value. 37 func (e *EnumSetting) String(sv *Values) string { 38 enumID := e.Get(sv) 39 if str, ok := e.enumValues[enumID]; ok { 40 return str 41 } 42 return fmt.Sprintf("unknown(%d)", enumID) 43 } 44 45 // ParseEnum returns the enum value, and a boolean that indicates if it was parseable. 46 func (e *EnumSetting) ParseEnum(raw string) (int64, bool) { 47 rawLower := strings.ToLower(raw) 48 for k, v := range e.enumValues { 49 if v == rawLower { 50 return k, true 51 } 52 } 53 // Attempt to parse the string as an integer since it isn't a valid enum string. 54 v, err := strconv.ParseInt(raw, 10, 64) 55 if err != nil { 56 return 0, false 57 } 58 _, ok := e.enumValues[v] 59 return v, ok 60 } 61 62 // GetAvailableValuesAsHint returns the possible enum settings as a string that 63 // can be provided as an error hint to a user. 64 func (e *EnumSetting) GetAvailableValuesAsHint() string { 65 // First stabilize output by sorting by key. 66 valIdxs := make([]int, 0, len(e.enumValues)) 67 for i := range e.enumValues { 68 valIdxs = append(valIdxs, int(i)) 69 } 70 sort.Ints(valIdxs) 71 72 // Now use those indices 73 vals := make([]string, 0, len(e.enumValues)) 74 for _, enumIdx := range valIdxs { 75 vals = append(vals, fmt.Sprintf("%d: %s", enumIdx, e.enumValues[int64(enumIdx)])) 76 } 77 return "Available values: " + strings.Join(vals, ", ") 78 } 79 80 func (e *EnumSetting) set(sv *Values, k int64) error { 81 if _, ok := e.enumValues[k]; !ok { 82 return errors.Errorf("unrecognized value %d", k) 83 } 84 return e.IntSetting.set(sv, k) 85 } 86 87 func enumValuesToDesc(enumValues map[int64]string) string { 88 var buffer bytes.Buffer 89 values := make([]int64, 0, len(enumValues)) 90 for k := range enumValues { 91 values = append(values, k) 92 } 93 sort.Slice(values, func(i, j int) bool { return values[i] < values[j] }) 94 95 buffer.WriteString("[") 96 for i, k := range values { 97 if i > 0 { 98 buffer.WriteString(", ") 99 } 100 fmt.Fprintf(&buffer, "%s = %d", strings.ToLower(enumValues[k]), k) 101 } 102 buffer.WriteString("]") 103 return buffer.String() 104 } 105 106 // RegisterPublicEnumSetting defines a new setting with type int and makes it public. 107 func RegisterPublicEnumSetting( 108 key, desc string, defaultValue string, enumValues map[int64]string, 109 ) *EnumSetting { 110 s := RegisterEnumSetting(key, desc, defaultValue, enumValues) 111 s.SetVisibility(Public) 112 return s 113 } 114 115 // RegisterEnumSetting defines a new setting with type int. 116 func RegisterEnumSetting( 117 key, desc string, defaultValue string, enumValues map[int64]string, 118 ) *EnumSetting { 119 enumValuesLower := make(map[int64]string) 120 var i int64 121 var found bool 122 for k, v := range enumValues { 123 enumValuesLower[k] = strings.ToLower(v) 124 if v == defaultValue { 125 i = k 126 found = true 127 } 128 } 129 130 if !found { 131 panic(fmt.Sprintf("enum registered with default value %s not in map %s", defaultValue, enumValuesToDesc(enumValuesLower))) 132 } 133 134 setting := &EnumSetting{ 135 IntSetting: IntSetting{defaultValue: i}, 136 enumValues: enumValuesLower, 137 } 138 139 register(key, fmt.Sprintf("%s %s", desc, enumValuesToDesc(enumValues)), setting) 140 return setting 141 }