-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathflag_map_impl.go
More file actions
138 lines (122 loc) · 3.4 KB
/
flag_map_impl.go
File metadata and controls
138 lines (122 loc) · 3.4 KB
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package cli
import (
"encoding/json"
"fmt"
"reflect"
"sort"
"strings"
)
// MapBase wraps map[string]T to satisfy flag.Value
type MapBase[T any, C any, VC ValueCreator[T, C]] struct {
dict *map[string]T
hasBeenSet bool
value Value
multiValueConfig multiValueParsingConfig
}
func (i MapBase[T, C, VC]) Create(val map[string]T, p *map[string]T, c C) Value {
*p = map[string]T{}
for k, v := range val {
(*p)[k] = v
}
var t T
np := new(T)
var vc VC
return &MapBase[T, C, VC]{
dict: p,
value: vc.Create(t, np, c),
}
}
// NewMapBase makes a *MapBase with default values
func NewMapBase[T any, C any, VC ValueCreator[T, C]](defaults map[string]T) *MapBase[T, C, VC] {
return &MapBase[T, C, VC]{
dict: &defaults,
}
}
// configuration of slicing
func (i *MapBase[T, C, VC]) setMultiValueParsingConfig(c multiValueParsingConfig) {
i.multiValueConfig = c
mvc := &i.multiValueConfig
tracef(
"set map parsing config - keyValueSeparator '%s', slice separator '%s', disable separator:%v",
mvc.MapFlagKeyValueSeparator,
mvc.SliceFlagSeparator,
mvc.DisableSliceFlagSeparator,
)
}
// Set parses the value and appends it to the list of values
func (i *MapBase[T, C, VC]) Set(value string) error {
if !i.hasBeenSet {
*i.dict = map[string]T{}
i.hasBeenSet = true
}
if strings.HasPrefix(value, slPfx) {
// Deserializing assumes overwrite
_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &i.dict)
i.hasBeenSet = true
return nil
}
mvc := &i.multiValueConfig
keyValueSeparator := mvc.MapFlagKeyValueSeparator
if len(keyValueSeparator) == 0 {
keyValueSeparator = defaultMapFlagKeyValueSeparator
}
tracef(
"splitting map value '%s', keyValueSeparator '%s', slice separator '%s', disable separator:%v",
value,
keyValueSeparator,
mvc.SliceFlagSeparator,
mvc.DisableSliceFlagSeparator,
)
for _, item := range flagSplitMultiValues(value, mvc.SliceFlagSeparator, mvc.DisableSliceFlagSeparator) {
key, value, ok := strings.Cut(item, keyValueSeparator)
if !ok {
return fmt.Errorf("item %q is missing separator %q", item, keyValueSeparator)
}
if err := i.value.Set(value); err != nil {
return err
}
(*i.dict)[key] = i.value.Get().(T)
}
return nil
}
// String returns a readable representation of this value (for usage defaults)
func (i *MapBase[T, C, VC]) String() string {
v := i.Value()
var t T
if reflect.TypeOf(t).Kind() == reflect.String {
return fmt.Sprintf("%v", v)
}
return fmt.Sprintf("%T{%s}", v, i.ToString(v))
}
// Serialize allows MapBase to fulfill Serializer
func (i *MapBase[T, C, VC]) Serialize() string {
jsonBytes, _ := json.Marshal(i.dict)
return fmt.Sprintf("%s%s", slPfx, string(jsonBytes))
}
// Value returns the mapping of values set by this flag
func (i *MapBase[T, C, VC]) Value() map[string]T {
if i.dict == nil {
return map[string]T{}
}
return *i.dict
}
// Get returns the mapping of values set by this flag
func (i *MapBase[T, C, VC]) Get() interface{} {
return *i.dict
}
func (i MapBase[T, C, VC]) ToString(t map[string]T) string {
var defaultVals []string
var vc VC
for _, k := range sortedKeys(t) {
defaultVals = append(defaultVals, k+defaultMapFlagKeyValueSeparator+vc.ToString(t[k]))
}
return strings.Join(defaultVals, ", ")
}
func sortedKeys[T any](dict map[string]T) []string {
keys := make([]string, 0, len(dict))
for k := range dict {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}