@@ -49,9 +49,36 @@ type validatingObjectWalker struct {
49
49
50
50
// internal housekeeping--don't set when constructing.
51
51
inLeaf bool // Set to true if we're in a "big leaf"--atomic map/list
52
+
53
+ // Allocate only as many walkers as needed for the depth by storing them here.
54
+ spareWalkers * []* validatingObjectWalker
55
+ }
56
+
57
+ func (v * validatingObjectWalker ) prepareDescent (pe fieldpath.PathElement , tr schema.TypeRef ) * validatingObjectWalker {
58
+ if v .spareWalkers == nil {
59
+ // first descent.
60
+ v .spareWalkers = & []* validatingObjectWalker {}
61
+ }
62
+ var v2 * validatingObjectWalker
63
+ if n := len (* v .spareWalkers ); n > 0 {
64
+ v2 , * v .spareWalkers = (* v .spareWalkers )[n - 1 ], (* v .spareWalkers )[:n - 1 ]
65
+ } else {
66
+ v2 = & validatingObjectWalker {}
67
+ }
68
+ * v2 = * v
69
+ v2 .typeRef = tr
70
+ v2 .errorFormatter .descend (pe )
71
+ return v2
72
+ }
73
+
74
+ func (v * validatingObjectWalker ) finishDescent (v2 * validatingObjectWalker ) {
75
+ // if the descent caused a realloc, ensure that we reuse the buffer
76
+ // for the next sibling.
77
+ v .errorFormatter = v2 .errorFormatter .parent ()
78
+ * v .spareWalkers = append (* v .spareWalkers , v2 )
52
79
}
53
80
54
- func (v validatingObjectWalker ) validate () ValidationErrors {
81
+ func (v * validatingObjectWalker ) validate () ValidationErrors {
55
82
return resolveSchema (v .schema , v .typeRef , & v .value , v )
56
83
}
57
84
@@ -87,7 +114,7 @@ func (v *validatingObjectWalker) doNode() {
87
114
}
88
115
}
89
116
90
- func (v validatingObjectWalker ) doScalar (t schema.Scalar ) ValidationErrors {
117
+ func (v * validatingObjectWalker ) doScalar (t schema.Scalar ) ValidationErrors {
91
118
if errs := v .validateScalar (t , & v .value , "" ); len (errs ) > 0 {
92
119
return errs
93
120
}
@@ -98,7 +125,7 @@ func (v validatingObjectWalker) doScalar(t schema.Scalar) ValidationErrors {
98
125
return nil
99
126
}
100
127
101
- func (v validatingObjectWalker ) visitListItems (t schema.List , list * value.List ) (errs ValidationErrors ) {
128
+ func (v * validatingObjectWalker ) visitListItems (t schema.List , list * value.List ) (errs ValidationErrors ) {
102
129
observedKeys := map [string ]struct {}{}
103
130
for i , child := range list .Items {
104
131
pe , err := listItemToPathElement (t , i , child )
@@ -114,18 +141,17 @@ func (v validatingObjectWalker) visitListItems(t schema.List, list *value.List)
114
141
errs = append (errs , v .errorf ("duplicate entries for key %v" , keyStr )... )
115
142
}
116
143
observedKeys [keyStr ] = struct {}{}
117
- v2 := v
118
- v2 .errorFormatter .descend (pe )
144
+ v2 := v .prepareDescent (pe , t .ElementType )
119
145
v2 .value = child
120
- v2 .typeRef = t .ElementType
121
146
errs = append (errs , v2 .validate ()... )
122
147
123
148
v2 .doNode ()
149
+ v .finishDescent (v2 )
124
150
}
125
151
return errs
126
152
}
127
153
128
- func (v validatingObjectWalker ) doList (t schema.List ) (errs ValidationErrors ) {
154
+ func (v * validatingObjectWalker ) doList (t schema.List ) (errs ValidationErrors ) {
129
155
list , err := listValue (v .value )
130
156
if err != nil {
131
157
return v .error (err )
@@ -144,7 +170,7 @@ func (v validatingObjectWalker) doList(t schema.List) (errs ValidationErrors) {
144
170
return errs
145
171
}
146
172
147
- func (v validatingObjectWalker ) visitMapItems (t schema.Map , m * value.Map ) (errs ValidationErrors ) {
173
+ func (v * validatingObjectWalker ) visitMapItems (t schema.Map , m * value.Map ) (errs ValidationErrors ) {
148
174
fieldTypes := map [string ]schema.TypeRef {}
149
175
for i := range t .Fields {
150
176
// I don't want to use the loop variable since a reference
@@ -153,25 +179,27 @@ func (v validatingObjectWalker) visitMapItems(t schema.Map, m *value.Map) (errs
153
179
fieldTypes [f .Name ] = f .Type
154
180
}
155
181
156
- for _ , item := range m .Items {
157
- v2 := v
158
- name := item .Name
159
- v2 .errorFormatter .descend (fieldpath.PathElement {FieldName : & name })
160
- v2 .value = item .Value
182
+ for i := range m .Items {
183
+ item := & m .Items [i ]
184
+ pe := fieldpath.PathElement {FieldName : & item .Name }
161
185
162
- var ok bool
163
- if v2 .typeRef , ok = fieldTypes [name ]; ok {
186
+ if tr , ok := fieldTypes [item .Name ]; ok {
187
+ v2 := v .prepareDescent (pe , tr )
188
+ v2 .value = item .Value
164
189
errs = append (errs , v2 .validate ()... )
190
+ v .finishDescent (v2 )
165
191
} else {
166
- v2 .typeRef = t .ElementType
192
+ v2 := v .prepareDescent (pe , t .ElementType )
193
+ v2 .value = item .Value
167
194
errs = append (errs , v2 .validate ()... )
168
195
v2 .doNode ()
196
+ v .finishDescent (v2 )
169
197
}
170
198
}
171
199
return errs
172
200
}
173
201
174
- func (v validatingObjectWalker ) doMap (t schema.Map ) (errs ValidationErrors ) {
202
+ func (v * validatingObjectWalker ) doMap (t schema.Map ) (errs ValidationErrors ) {
175
203
m , err := mapValue (v .value )
176
204
if err != nil {
177
205
return v .error (err )
0 commit comments