@@ -49,9 +49,36 @@ type validatingObjectWalker struct {
4949
5050 // internal housekeeping--don't set when constructing.
5151 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 )
5279}
5380
54- func (v validatingObjectWalker ) validate () ValidationErrors {
81+ func (v * validatingObjectWalker ) validate () ValidationErrors {
5582 return resolveSchema (v .schema , v .typeRef , & v .value , v )
5683}
5784
@@ -87,7 +114,7 @@ func (v *validatingObjectWalker) doNode() {
87114 }
88115}
89116
90- func (v validatingObjectWalker ) doScalar (t schema.Scalar ) ValidationErrors {
117+ func (v * validatingObjectWalker ) doScalar (t schema.Scalar ) ValidationErrors {
91118 if errs := v .validateScalar (t , & v .value , "" ); len (errs ) > 0 {
92119 return errs
93120 }
@@ -98,7 +125,7 @@ func (v validatingObjectWalker) doScalar(t schema.Scalar) ValidationErrors {
98125 return nil
99126}
100127
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 ) {
102129 observedKeys := map [string ]struct {}{}
103130 for i , child := range list .Items {
104131 pe , err := listItemToPathElement (t , i , child )
@@ -114,18 +141,17 @@ func (v validatingObjectWalker) visitListItems(t schema.List, list *value.List)
114141 errs = append (errs , v .errorf ("duplicate entries for key %v" , keyStr )... )
115142 }
116143 observedKeys [keyStr ] = struct {}{}
117- v2 := v
118- v2 .errorFormatter .descend (pe )
144+ v2 := v .prepareDescent (pe , t .ElementType )
119145 v2 .value = child
120- v2 .typeRef = t .ElementType
121146 errs = append (errs , v2 .validate ()... )
122147
123148 v2 .doNode ()
149+ v .finishDescent (v2 )
124150 }
125151 return errs
126152}
127153
128- func (v validatingObjectWalker ) doList (t schema.List ) (errs ValidationErrors ) {
154+ func (v * validatingObjectWalker ) doList (t schema.List ) (errs ValidationErrors ) {
129155 list , err := listValue (v .value )
130156 if err != nil {
131157 return v .error (err )
@@ -144,7 +170,7 @@ func (v validatingObjectWalker) doList(t schema.List) (errs ValidationErrors) {
144170 return errs
145171}
146172
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 ) {
148174 fieldTypes := map [string ]schema.TypeRef {}
149175 for i := range t .Fields {
150176 // 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
153179 fieldTypes [f .Name ] = f .Type
154180 }
155181
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 }
161185
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
164189 errs = append (errs , v2 .validate ()... )
190+ v .finishDescent (v2 )
165191 } else {
166- v2 .typeRef = t .ElementType
192+ v2 := v .prepareDescent (pe , t .ElementType )
193+ v2 .value = item .Value
167194 errs = append (errs , v2 .validate ()... )
168195 v2 .doNode ()
196+ v .finishDescent (v2 )
169197 }
170198 }
171199 return errs
172200}
173201
174- func (v validatingObjectWalker ) doMap (t schema.Map ) (errs ValidationErrors ) {
202+ func (v * validatingObjectWalker ) doMap (t schema.Map ) (errs ValidationErrors ) {
175203 m , err := mapValue (v .value )
176204 if err != nil {
177205 return v .error (err )
0 commit comments