Skip to content

Commit 186edae

Browse files
apelisseAntoine Pelisse
authored andcommitted
Create Map interface (needs documentation)
1 parent 3b6dee9 commit 186edae

File tree

9 files changed

+169
-96
lines changed

9 files changed

+169
-96
lines changed

fieldpath/fromvalue.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ func (w *objectWalker) walk() {
6666
// If the map/struct were atomic, we'd break here, but we don't
6767
// have a schema, so we can't tell.
6868

69-
for key, val := range value.ValueMap(w.value) {
69+
value.ValueMap(w.value).Iterate(func(k string, val value.Value) bool {
7070
w2 := *w
71-
k := key
7271
w2.path = append(w.path, PathElement{FieldName: &k})
7372
w2.value = val
7473
w2.walk()
75-
}
74+
return true
75+
})
7676
return
7777
}
7878

@@ -105,7 +105,7 @@ func GuessBestListPathElement(index int, item value.Value) PathElement {
105105

106106
var keys value.FieldList
107107
for _, name := range AssociativeListCandidateFieldNames {
108-
f, ok := value.ValueMap(item)[name]
108+
f, ok := value.ValueMap(item).Get(name)
109109
if !ok {
110110
continue
111111
}

typed/helpers.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ func listValue(val value.Value) ([]interface{}, error) {
150150
}
151151

152152
// Returns the map, or an error. Reminder: nil is a valid map and might be returned.
153-
func mapValue(val value.Value) (map[string]interface{}, error) {
153+
func mapValue(val value.Value) (value.Map, error) {
154154
if val == nil {
155155
// Null is a valid map.
156156
return nil, nil
@@ -173,7 +173,7 @@ func keyedAssociativeListItemToPathElement(list *schema.List, index int, child v
173173
}
174174
keyMap := value.FieldList{}
175175
for _, fieldName := range list.Keys {
176-
if val, ok := value.ValueMap(child)[fieldName]; ok {
176+
if val, ok := value.ValueMap(child).Get(fieldName); ok {
177177
keyMap = append(keyMap, value.Field{Name: fieldName, Value: val})
178178
} else {
179179
return pe, fmt.Errorf("associative list with keys has an element that omits key field %q", fieldName)

typed/merge.go

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ func (w *mergingWalker) finishDescent(w2 *mergingWalker) {
148148
*w.spareWalkers = append(*w.spareWalkers, w2)
149149
}
150150

151-
func (w *mergingWalker) derefMap(prefix string, v *value.Value, dest *map[string]interface{}) (errs ValidationErrors) {
151+
func (w *mergingWalker) derefMap(prefix string, v *value.Value, dest *value.Map) (errs ValidationErrors) {
152152
// taking dest as input so that it can be called as a one-liner with
153153
// append.
154154
if v == nil {
@@ -298,29 +298,35 @@ func (w *mergingWalker) visitMapItem(t *schema.Map, out map[string]interface{},
298298
return nil
299299
}
300300

301-
func (w *mergingWalker) visitMapItems(t *schema.Map, lhs, rhs map[string]interface{}) (errs ValidationErrors) {
301+
func (w *mergingWalker) visitMapItems(t *schema.Map, lhs, rhs value.Map) (errs ValidationErrors) {
302302
out := map[string]interface{}{}
303303

304-
for key, val := range lhs {
305-
var rval *value.Value
306-
if rhs != nil {
307-
if item, ok := rhs[key]; ok {
308-
v := value.Value(item)
309-
rval = &v
304+
if lhs != nil {
305+
lhs.Iterate(func(key string, val value.Value) bool {
306+
var rval *value.Value
307+
if rhs != nil {
308+
if item, ok := rhs.Get(key); ok {
309+
v := value.Value(item)
310+
rval = &v
311+
}
310312
}
311-
}
312-
lval := value.Value(val)
313-
errs = append(errs, w.visitMapItem(t, out, key, &lval, rval)...)
313+
lval := value.Value(val)
314+
errs = append(errs, w.visitMapItem(t, out, key, &lval, rval)...)
315+
return true
316+
})
314317
}
315318

316-
for key, val := range rhs {
317-
if lhs != nil {
318-
if _, ok := lhs[key]; ok {
319-
continue
319+
if rhs != nil {
320+
rhs.Iterate(func(key string, val value.Value) bool {
321+
if lhs != nil {
322+
if _, ok := lhs.Get(key); ok {
323+
return true
324+
}
320325
}
321-
}
322-
rval := value.Value(val)
323-
errs = append(errs, w.visitMapItem(t, out, key, nil, &rval)...)
326+
rval := value.Value(val)
327+
errs = append(errs, w.visitMapItem(t, out, key, nil, &rval)...)
328+
return true
329+
})
324330
}
325331
if len(out) > 0 {
326332
v := value.Value(out)
@@ -331,14 +337,14 @@ func (w *mergingWalker) visitMapItems(t *schema.Map, lhs, rhs map[string]interfa
331337
}
332338

333339
func (w *mergingWalker) doMap(t *schema.Map) (errs ValidationErrors) {
334-
var lhs, rhs map[string]interface{}
340+
var lhs, rhs value.Map
335341
w.derefMap("lhs: ", w.lhs, &lhs)
336342
w.derefMap("rhs: ", w.rhs, &rhs)
337343

338344
// If both lhs and rhs are empty/null, treat it as a
339345
// leaf: this helps preserve the empty/null
340346
// distinction.
341-
emptyPromoteToLeaf := len(lhs) == 0 && len(rhs) == 0
347+
emptyPromoteToLeaf := (lhs == nil || lhs.Length() == 0) && (rhs == nil || rhs.Length() == 0)
342348

343349
if t.ElementRelationship == schema.Atomic || emptyPromoteToLeaf {
344350
w.doLeaf()

typed/remove.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func (w *removingWalker) doMap(t *schema.Map) ValidationErrors {
7676
m := value.ValueMap(*w.value)
7777

7878
// If map is null, empty, or atomic just return
79-
if len(m) == 0 || t.ElementRelationship == schema.Atomic {
79+
if m == nil || m.Length() == 0 || t.ElementRelationship == schema.Atomic {
8080
return nil
8181
}
8282

@@ -86,25 +86,25 @@ func (w *removingWalker) doMap(t *schema.Map) ValidationErrors {
8686
}
8787

8888
newMap := map[string]interface{}{}
89-
for key, val := range m {
90-
k := key
89+
m.Iterate(func(k string, val value.Value) bool {
9190
pe := fieldpath.PathElement{FieldName: &k}
9291
path, _ := fieldpath.MakePath(pe)
9392
fieldType := t.ElementType
94-
if ft, ok := fieldTypes[key]; ok {
93+
if ft, ok := fieldTypes[k]; ok {
9594
fieldType = ft
9695
} else {
9796
if w.toRemove.Has(path) {
98-
continue
97+
return true
9998
}
10099
}
101100
if subset := w.toRemove.WithPrefix(pe); !subset.Empty() {
102101
v := value.Value(val)
103102
removeItemsWithSchema(&v, subset, w.schema, fieldType)
104103
val = v
105104
}
106-
newMap[key] = val
107-
}
105+
newMap[k] = val
106+
return true
107+
})
108108
if len(newMap) > 0 {
109109
*w.value = newMap
110110
} else {

typed/tofieldset.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,9 @@ func (v *toFieldSetWalker) doList(t *schema.List) (errs ValidationErrors) {
121121
return errs
122122
}
123123

124-
func (v *toFieldSetWalker) visitMapItems(t *schema.Map, m map[string]interface{}) (errs ValidationErrors) {
125-
for key, val := range m {
126-
k := key
127-
pe := fieldpath.PathElement{FieldName: &k}
124+
func (v *toFieldSetWalker) visitMapItems(t *schema.Map, m value.Map) (errs ValidationErrors) {
125+
m.Iterate(func(key string, val value.Value) bool {
126+
pe := fieldpath.PathElement{FieldName: &key}
128127

129128
tr := t.ElementType
130129
if sf, ok := t.FindField(key); ok {
@@ -137,8 +136,8 @@ func (v *toFieldSetWalker) visitMapItems(t *schema.Map, m map[string]interface{}
137136
v2.set.Insert(v2.path)
138137
}
139138
v.finishDescent(v2)
140-
141-
}
139+
return true
140+
})
142141
return errs
143142
}
144143

typed/union.go

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,14 @@ func normalizeUnions(w *mergingWalker) error {
3434
return nil
3535
}
3636

37-
var old map[string]interface{}
37+
var old value.Map
3838
if w.lhs != nil {
3939
old = value.ValueMap(*w.lhs)
4040
}
4141
for _, union := range atom.Map.Unions {
42-
v := value.ValueMap(*w.out)
43-
if err := newUnion(&union).Normalize(old, value.ValueMap(*w.rhs), v); err != nil {
42+
if err := newUnion(&union).Normalize(old, value.ValueMap(*w.rhs), value.ValueMap(*w.out)); err != nil {
4443
return err
4544
}
46-
*w.out = v
4745
}
4846
return nil
4947
}
@@ -58,16 +56,14 @@ func normalizeUnionsApply(w *mergingWalker) error {
5856
return nil
5957
}
6058

61-
var old map[string]interface{}
59+
var old value.Map
6260
if w.lhs != nil {
6361
old = value.ValueMap(*w.lhs)
6462
}
6563
for _, union := range atom.Map.Unions {
66-
v := value.ValueMap(*w.out)
67-
if err := newUnion(&union).NormalizeApply(old, value.ValueMap(*w.rhs), v); err != nil {
64+
if err := newUnion(&union).NormalizeApply(old, value.ValueMap(*w.rhs), value.ValueMap(*w.out)); err != nil {
6865
return err
6966
}
70-
*w.out = v
7167
}
7268
return nil
7369
}
@@ -109,18 +105,18 @@ type discriminator struct {
109105
name string
110106
}
111107

112-
func (d *discriminator) Set(m map[string]interface{}, v discriminated) {
108+
func (d *discriminator) Set(m value.Map, v discriminated) {
113109
if d == nil {
114110
return
115111
}
116-
m[d.name] = string(v)
112+
m.Set(d.name, string(v))
117113
}
118114

119-
func (d *discriminator) Get(m map[string]interface{}) discriminated {
115+
func (d *discriminator) Get(m value.Map) discriminated {
120116
if d == nil || m == nil {
121117
return ""
122118
}
123-
val, ok := m[d.name]
119+
val, ok := m.Get(d.name)
124120
if !ok {
125121
return ""
126122
}
@@ -134,13 +130,13 @@ type fieldsSet map[field]struct{}
134130

135131
// newFieldsSet returns a map of the fields that are part of the union and are set
136132
// in the given map.
137-
func newFieldsSet(m map[string]interface{}, fields []field) fieldsSet {
133+
func newFieldsSet(m value.Map, fields []field) fieldsSet {
138134
if m == nil {
139135
return nil
140136
}
141137
set := fieldsSet{}
142138
for _, f := range fields {
143-
if subField, ok := m[string(f)]; ok && subField != nil {
139+
if subField, ok := m.Get(string(f)); ok && subField != nil {
144140
set.Add(f)
145141
}
146142
}
@@ -216,15 +212,15 @@ func newUnion(su *schema.Union) *union {
216212

217213
// clear removes all the fields in map that are part of the union, but
218214
// the one we decided to keep.
219-
func (u *union) clear(m map[string]interface{}, f field) {
215+
func (u *union) clear(m value.Map, f field) {
220216
for _, fieldName := range u.f {
221217
if field(fieldName) != f {
222-
delete(m, string(fieldName))
218+
m.Delete(string(fieldName))
223219
}
224220
}
225221
}
226222

227-
func (u *union) Normalize(old, new, out map[string]interface{}) error {
223+
func (u *union) Normalize(old, new, out value.Map) error {
228224
os := newFieldsSet(old, u.f)
229225
ns := newFieldsSet(new, u.f)
230226
diff := ns.Difference(os)
@@ -252,7 +248,7 @@ func (u *union) Normalize(old, new, out map[string]interface{}) error {
252248
return nil
253249
}
254250

255-
func (u *union) NormalizeApply(applied, merged, out map[string]interface{}) error {
251+
func (u *union) NormalizeApply(applied, merged, out value.Map) error {
256252
as := newFieldsSet(applied, u.f)
257253
if len(as) > 1 {
258254
return fmt.Errorf("more than one field of union applied: %v", as)

typed/validate.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -155,23 +155,22 @@ func (v *validatingObjectWalker) doList(t *schema.List) (errs ValidationErrors)
155155
return errs
156156
}
157157

158-
func (v *validatingObjectWalker) visitMapItems(t *schema.Map, m map[string]interface{}) (errs ValidationErrors) {
159-
// Avoiding the closure on m.Iterate here significantly improves
160-
// performance, so we have to switch on each type of maps.
161-
for key, val := range m {
162-
k := key
163-
pe := fieldpath.PathElement{FieldName: &k}
158+
func (v *validatingObjectWalker) visitMapItems(t *schema.Map, m value.Map) (errs ValidationErrors) {
159+
m.Iterate(func(key string, val value.Value) bool {
160+
pe := fieldpath.PathElement{FieldName: &key}
164161
tr := t.ElementType
165162
if sf, ok := t.FindField(key); ok {
166163
tr = sf.Type
167164
} else if (t.ElementType == schema.TypeRef{}) {
168-
return append(errs, errorf("field not declared in schema").WithPrefix(pe.String())...)
165+
errs = append(errs, errorf("field not declared in schema").WithPrefix(pe.String())...)
166+
return false
169167
}
170168
v2 := v.prepareDescent(tr)
171169
v2.value = val
172170
errs = append(errs, v2.validate()...)
173171
v.finishDescent(v2)
174-
}
172+
return true
173+
})
175174
return errs
176175
}
177176

0 commit comments

Comments
 (0)