8 // Flatten takes a structure and turns into a flat map[string]string.
10 // Within the "thing" parameter, only primitive values are allowed. Structs are
11 // not supported. Therefore, it can only be slices, maps, primitives, and
12 // any combination of those together.
14 // See the tests for examples of what inputs are turned into.
15 func Flatten(thing map[string]interface{}) Map {
16 result := make(map[string]string)
18 for k, raw := range thing {
19 flatten(result, k, reflect.ValueOf(raw))
25 func flatten(result map[string]string, prefix string, v reflect.Value) {
26 if v.Kind() == reflect.Interface {
33 result[prefix] = "true"
35 result[prefix] = "false"
38 result[prefix] = fmt.Sprintf("%d", v.Int())
40 flattenMap(result, prefix, v)
42 flattenSlice(result, prefix, v)
44 result[prefix] = v.String()
46 panic(fmt.Sprintf("Unknown: %s", v))
50 func flattenMap(result map[string]string, prefix string, v reflect.Value) {
51 for _, k := range v.MapKeys() {
52 if k.Kind() == reflect.Interface {
56 if k.Kind() != reflect.String {
57 panic(fmt.Sprintf("%s: map key is not string: %s", prefix, k))
60 flatten(result, fmt.Sprintf("%s.%s", prefix, k.String()), v.MapIndex(k))
64 func flattenSlice(result map[string]string, prefix string, v reflect.Value) {
67 result[prefix+"#"] = fmt.Sprintf("%d", v.Len())
68 for i := 0; i < v.Len(); i++ {
69 flatten(result, fmt.Sprintf("%s%d", prefix, i), v.Index(i))