1package structs
2
3import (
4	"fmt"
5	"strings"
6)
7
8type dotWalker struct {
9	data  string
10	first bool
11}
12
13func newDotWalker(data string) dotWalker {
14	return dotWalker{data: data, first: true}
15}
16
17func (d dotWalker) Empty() bool { return d.data == "" }
18
19func (d *dotWalker) Next() (out string) {
20	if d.data == "" {
21		return ""
22	} else if d.data[0] == '.' {
23		if d.first {
24			d.first = false
25			return ""
26		}
27		d.data = d.data[1:]
28	}
29	d.first = false
30	dot := strings.IndexByte(d.data, '.')
31	if dot < 0 {
32		dot = len(d.data)
33	}
34	out, d.data = d.data[:dot], d.data[dot:]
35	return out
36}
37
38//
39//
40//
41
42type callbacks []func()
43
44func (c *callbacks) Reset() {
45	for i := range *c {
46		(*c)[i] = nil
47	}
48	*c = (*c)[:0]
49}
50
51func (c *callbacks) Append(cb func()) {
52	*c = append(*c, cb)
53}
54
55func (c *callbacks) Run() {
56	for len(*c) > 0 {
57		cb := (*c)[len(*c)-1]
58		(*c)[len(*c)-1] = nil
59		*c = (*c)[:len(*c)-1]
60		cb()
61	}
62}
63
64//
65//
66//
67
68func dotJoin(base, part string) string {
69	if base == "" {
70		return part
71	}
72	return base + "." + part
73}
74
75//
76//
77//
78
79func gatherKeys(from interface{}, base string, into map[string]struct{}) map[string]struct{} {
80	if into == nil {
81		into = make(map[string]struct{})
82	}
83	switch from := from.(type) {
84	case map[string]interface{}:
85		for key, value := range from {
86			into = gatherKeys(value, dotJoin(base, key), into)
87		}
88
89	case []interface{}:
90		for key, value := range from {
91			into = gatherKeys(value, dotJoin(base, fmt.Sprint(key)), into)
92		}
93
94	default:
95		if base != "" {
96			into[base] = struct{}{}
97		}
98	}
99
100	return into
101}
102