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
|
package api
import (
"encoding/json"
"fmt"
"strconv"
)
// ConfigMap type is used to hold incus config. In contrast to plain
// map[string]string it provides unmarshal methods for JSON and YAML, which
// gracefully handle numbers and bools.
//
// swagger:model
// swagger:type object
//
// Example: {"user.mykey": "foo"}
type ConfigMap map[string]string
// Backwards compatibility tests.
var (
_ map[string]string = ConfigMap{}
_ ConfigMap = map[string]string{}
)
// UnmarshalJSON implements json.Unmarshaler interface.
func (m *ConfigMap) UnmarshalJSON(data []byte) error {
var raw map[string]any
err := json.Unmarshal(data, &raw)
if err != nil {
return fmt.Errorf("JSON data not valid for ConfigMap: %w", err)
}
return m.fromMapStringAny(raw)
}
// UnmarshalYAML implements yaml.Unmarshaler interface.
func (m *ConfigMap) UnmarshalYAML(unmarshal func(any) error) error {
var raw map[string]any
err := unmarshal(&raw)
if err != nil {
return fmt.Errorf("YAML data not valid for ConfigMap: %w", err)
}
return m.fromMapStringAny(raw)
}
func (m *ConfigMap) fromMapStringAny(raw map[string]any) error {
if raw == nil {
return nil
}
result := *m
if result == nil {
result = make(ConfigMap, len(raw))
}
for k, v := range raw {
switch val := v.(type) {
case string:
result[k] = val
case int:
result[k] = strconv.FormatInt(int64(val), 10)
case uint64:
result[k] = strconv.FormatUint(val, 10)
case float64:
if val == float64(int64(val)) {
result[k] = strconv.FormatInt(int64(val), 10)
} else {
result[k] = strconv.FormatFloat(val, 'g', -1, 64)
}
case bool:
result[k] = strconv.FormatBool(val)
case nil:
result[k] = ""
default:
return fmt.Errorf("type %T is not supported in %T", v, m)
}
}
*m = result
return nil
}
|