|
1 | 1 | package spec |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "reflect" |
| 5 | + "slices" |
4 | 6 | "strings" |
5 | 7 | ) |
6 | 8 |
|
@@ -57,62 +59,136 @@ func (s *Segment) String() string { |
57 | 59 | // Select selects and returns values from current or root, for each of s's |
58 | 60 | // selectors. Defined by the [Selector] interface. |
59 | 61 | func (s *Segment) Select(current, root any) []any { |
60 | | - ret := []any{} |
| 62 | + ret := make([]any, 0, len(s.selectors)) |
61 | 63 | for _, sel := range s.selectors { |
62 | 64 | ret = append(ret, sel.Select(current, root)...) |
63 | 65 | } |
64 | 66 | if s.descendant { |
65 | 67 | ret = append(ret, s.descend(current, root)...) |
66 | 68 | } |
67 | | - return ret |
| 69 | + return slices.Clip(ret) |
68 | 70 | } |
69 | 71 |
|
70 | 72 | // SelectLocated selects and returns values as [LocatedNode] values from |
71 | 73 | // current or root for each of seg's selectors. Defined by the [Selector] |
72 | 74 | // interface. |
73 | 75 | func (s *Segment) SelectLocated(current, root any, parent NormalizedPath) []*LocatedNode { |
74 | | - ret := []*LocatedNode{} |
| 76 | + ret := make([]*LocatedNode, 0, len(s.selectors)) |
75 | 77 | for _, sel := range s.selectors { |
76 | 78 | ret = append(ret, sel.SelectLocated(current, root, parent)...) |
77 | 79 | } |
78 | 80 | if s.descendant { |
79 | 81 | ret = append(ret, s.descendLocated(current, root, parent)...) |
80 | 82 | } |
81 | | - return ret |
| 83 | + return slices.Clip(ret) |
82 | 84 | } |
83 | 85 |
|
84 | 86 | // descend recursively executes [Segment.Select] for each value in current |
85 | 87 | // and/or root and its descendants and returns the results. |
86 | 88 | func (s *Segment) descend(current, root any) []any { |
87 | | - ret := []any{} |
88 | 89 | switch val := current.(type) { |
89 | 90 | case []any: |
| 91 | + ret := make([]any, 0, len(val)) |
90 | 92 | for _, v := range val { |
91 | 93 | ret = append(ret, s.Select(v, root)...) |
92 | 94 | } |
| 95 | + return slices.Clip(ret) |
93 | 96 | case map[string]any: |
| 97 | + ret := make([]any, 0, len(val)) |
94 | 98 | for _, v := range val { |
95 | 99 | ret = append(ret, s.Select(v, root)...) |
96 | 100 | } |
| 101 | + return slices.Clip(ret) |
| 102 | + default: |
| 103 | + value := reflect.ValueOf(current) |
| 104 | + switch value.Kind() { |
| 105 | + case reflect.Slice: |
| 106 | + // Descend into any other slice that contains slices or maps. |
| 107 | + switch value.Type().Elem().Kind() { |
| 108 | + case reflect.Slice, reflect.Map: |
| 109 | + ret := make([]any, 0, value.Len()) |
| 110 | + for i := range value.Len() { |
| 111 | + ret = append(ret, s.Select(value.Index(i).Interface(), root)...) |
| 112 | + } |
| 113 | + return slices.Clip(ret) |
| 114 | + default: |
| 115 | + return make([]any, 0) |
| 116 | + } |
| 117 | + case reflect.Map: |
| 118 | + // Descend into any map[string]* that contains slices or maps. |
| 119 | + if value.Type().Key().Kind() != reflect.String { |
| 120 | + return make([]any, 0) |
| 121 | + } |
| 122 | + switch value.Type().Elem().Kind() { |
| 123 | + case reflect.Slice, reflect.Map: |
| 124 | + ret := make([]any, 0, value.Len()) |
| 125 | + for _, k := range value.MapKeys() { |
| 126 | + ret = append(ret, s.Select(value.MapIndex(k).Interface(), root)...) |
| 127 | + } |
| 128 | + return slices.Clip(ret) |
| 129 | + default: |
| 130 | + return make([]any, 0) |
| 131 | + } |
| 132 | + default: |
| 133 | + return make([]any, 0) |
| 134 | + } |
97 | 135 | } |
98 | | - return ret |
99 | 136 | } |
100 | 137 |
|
101 | 138 | // descend recursively executes [q] for each value in current and/or root and |
102 | 139 | // its descendants and returns the results. |
103 | 140 | func (s *Segment) descendLocated(current, root any, parent NormalizedPath) []*LocatedNode { |
104 | | - ret := []*LocatedNode{} |
105 | 141 | switch val := current.(type) { |
106 | 142 | case []any: |
| 143 | + ret := make([]*LocatedNode, 0, len(val)) |
107 | 144 | for i, v := range val { |
108 | 145 | ret = append(ret, s.SelectLocated(v, root, append(parent, Index(i)))...) |
109 | 146 | } |
| 147 | + return slices.Clip(ret) |
110 | 148 | case map[string]any: |
| 149 | + ret := make([]*LocatedNode, 0, len(val)) |
111 | 150 | for k, v := range val { |
112 | 151 | ret = append(ret, s.SelectLocated(v, root, append(parent, Name(k)))...) |
113 | 152 | } |
| 153 | + return slices.Clip(ret) |
| 154 | + default: |
| 155 | + value := reflect.ValueOf(current) |
| 156 | + switch value.Kind() { |
| 157 | + case reflect.Slice: |
| 158 | + // Descend into any other slice that contains slices or maps. |
| 159 | + switch value.Type().Elem().Kind() { |
| 160 | + case reflect.Slice, reflect.Map: |
| 161 | + ret := make([]*LocatedNode, 0, value.Len()) |
| 162 | + for i := range value.Len() { |
| 163 | + ret = append(ret, s.SelectLocated( |
| 164 | + value.Index(i).Interface(), root, append(parent, Index(i)), |
| 165 | + )...) |
| 166 | + } |
| 167 | + return slices.Clip(ret) |
| 168 | + default: |
| 169 | + return make([]*LocatedNode, 0) |
| 170 | + } |
| 171 | + case reflect.Map: |
| 172 | + // Descend into any map[string]* that contains slices or maps. |
| 173 | + if value.Type().Key().Kind() != reflect.String { |
| 174 | + return make([]*LocatedNode, 0) |
| 175 | + } |
| 176 | + switch value.Type().Elem().Kind() { |
| 177 | + case reflect.Slice, reflect.Map: |
| 178 | + ret := make([]*LocatedNode, 0, value.Len()) |
| 179 | + for _, k := range value.MapKeys() { |
| 180 | + ret = append(ret, s.SelectLocated( |
| 181 | + value.MapIndex(k).Interface(), root, append(parent, Name(k.String())), |
| 182 | + )...) |
| 183 | + } |
| 184 | + return slices.Clip(ret) |
| 185 | + default: |
| 186 | + return make([]*LocatedNode, 0) |
| 187 | + } |
| 188 | + default: |
| 189 | + return make([]*LocatedNode, 0) |
| 190 | + } |
114 | 191 | } |
115 | | - return ret |
116 | 192 | } |
117 | 193 |
|
118 | 194 | // isSingular returns true if the segment selects at most one node. Defined by |
|
0 commit comments