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