@@ -20,11 +20,6 @@ const (
2020 pointerSeparator = `/`
2121)
2222
23- var (
24- jsonPointableType = reflect .TypeOf (new (JSONPointable )).Elem ()
25- jsonSetableType = reflect .TypeOf (new (JSONSetable )).Elem ()
26- )
27-
2823// JSONPointable is an interface for structs to implement when they need to customize the
2924// json pointer process
3025type JSONPointable interface {
@@ -174,7 +169,7 @@ func (p *Pointer) set(node, data any, nameProvider *jsonname.NameProvider) error
174169 nameProvider = jsonname .DefaultJSONNameProvider
175170 }
176171
177- // Full document when empty
172+ // full document when empty
178173 if len (p .referenceTokens ) == 0 {
179174 return nil
180175 }
@@ -188,82 +183,76 @@ func (p *Pointer) set(node, data any, nameProvider *jsonname.NameProvider) error
188183 return setSingleImpl (node , data , decodedToken , nameProvider )
189184 }
190185
191- // Check for nil during traversal
192- if isNil ( node ) {
193- return fmt . Errorf ( "cannot traverse through nil value at %q: %w" , decodedToken , ErrPointer )
186+ next , err := p . resolveNodeForToken ( node , decodedToken , nameProvider )
187+ if err != nil {
188+ return err
194189 }
195190
196- rValue := reflect . Indirect ( reflect . ValueOf ( node ))
197- kind := rValue . Kind ()
191+ node = next
192+ }
198193
199- if rValue .Type ().Implements (jsonPointableType ) {
200- pointable , ok := node .(JSONPointable )
201- if ! ok {
202- panic (fmt .Errorf ("internal error: expected a JSONPointable but got %T: %w" , node , ErrPointer ))
203- }
204- r , err := pointable .JSONLookup (decodedToken )
205- if err != nil {
206- return err
207- }
194+ return nil
195+ }
208196
209- fld := reflect .ValueOf (r )
210- if fld .CanAddr () && fld .Kind () != reflect .Interface && fld .Kind () != reflect .Map && fld .Kind () != reflect .Slice && fld .Kind () != reflect .Pointer {
211- node = fld .Addr ().Interface ()
212- continue
213- }
214- node = r
215- continue
197+ func (p * Pointer ) resolveNodeForToken (node any , decodedToken string , nameProvider * jsonname.NameProvider ) (next any , err error ) {
198+ // check for nil during traversal
199+ if isNil (node ) {
200+ return nil , fmt .Errorf ("cannot traverse through nil value at %q: %w" , decodedToken , ErrPointer )
201+ }
202+
203+ pointable , ok := node .(JSONPointable )
204+ if ok {
205+ r , err := pointable .JSONLookup (decodedToken )
206+ if err != nil {
207+ return nil , err
216208 }
217209
218- switch kind { //nolint:exhaustive
219- case reflect .Struct :
220- nm , ok := nameProvider .GetGoNameForType (rValue .Type (), decodedToken )
221- if ! ok {
222- return fmt .Errorf ("object has no field %q: %w" , decodedToken , ErrPointer )
223- }
224- fld := rValue .FieldByName (nm )
225- if fld .CanAddr () && fld .Kind () != reflect .Interface && fld .Kind () != reflect .Map && fld .Kind () != reflect .Slice && fld .Kind () != reflect .Pointer {
226- node = fld .Addr ().Interface ()
227- continue
228- }
229- node = fld .Interface ()
210+ fld := reflect .ValueOf (r )
211+ if fld .CanAddr () && fld .Kind () != reflect .Interface && fld .Kind () != reflect .Map && fld .Kind () != reflect .Slice && fld .Kind () != reflect .Pointer {
212+ return fld .Addr ().Interface (), nil
213+ }
230214
231- case reflect .Map :
232- kv := reflect .ValueOf (decodedToken )
233- mv := rValue .MapIndex (kv )
215+ return r , nil
216+ }
234217
235- if ! mv .IsValid () {
236- return fmt .Errorf ("object has no key %q: %w" , decodedToken , ErrPointer )
237- }
238- if mv .CanAddr () && mv .Kind () != reflect .Interface && mv .Kind () != reflect .Map && mv .Kind () != reflect .Slice && mv .Kind () != reflect .Pointer {
239- node = mv .Addr ().Interface ()
240- continue
241- }
242- node = mv .Interface ()
218+ rValue := reflect .Indirect (reflect .ValueOf (node ))
219+ kind := rValue .Kind ()
243220
244- case reflect .Slice :
245- tokenIndex , err := strconv .Atoi (decodedToken )
246- if err != nil {
247- return err
248- }
249- sLength := rValue .Len ()
250- if tokenIndex < 0 || tokenIndex >= sLength {
251- return fmt .Errorf ("index out of bounds array[0,%d] index '%d': %w" , sLength , tokenIndex , ErrPointer )
252- }
221+ switch kind { //nolint:exhaustive
222+ case reflect .Struct :
223+ nm , ok := nameProvider .GetGoNameForType (rValue .Type (), decodedToken )
224+ if ! ok {
225+ return nil , fmt .Errorf ("object has no field %q: %w" , decodedToken , ErrPointer )
226+ }
253227
254- elem := rValue .Index (tokenIndex )
255- if elem .CanAddr () && elem .Kind () != reflect .Interface && elem .Kind () != reflect .Map && elem .Kind () != reflect .Slice && elem .Kind () != reflect .Pointer {
256- node = elem .Addr ().Interface ()
257- continue
258- }
259- node = elem .Interface ()
228+ return typeFromValue (rValue .FieldByName (nm )), nil
260229
261- default :
262- return fmt .Errorf ("invalid token reference %q: %w" , decodedToken , ErrPointer )
230+ case reflect .Map :
231+ kv := reflect .ValueOf (decodedToken )
232+ mv := rValue .MapIndex (kv )
233+
234+ if ! mv .IsValid () {
235+ return nil , fmt .Errorf ("object has no key %q: %w" , decodedToken , ErrPointer )
263236 }
264- }
265237
266- return nil
238+ return typeFromValue (mv ), nil
239+
240+ case reflect .Slice :
241+ tokenIndex , err := strconv .Atoi (decodedToken )
242+ if err != nil {
243+ return nil , errors .Join (err , ErrPointer )
244+ }
245+
246+ sLength := rValue .Len ()
247+ if tokenIndex < 0 || tokenIndex >= sLength {
248+ return nil , fmt .Errorf ("index out of bounds array[0,%d] index '%d': %w" , sLength , tokenIndex , ErrPointer )
249+ }
250+
251+ return typeFromValue (rValue .Index (tokenIndex )), nil
252+
253+ default :
254+ return nil , fmt .Errorf ("invalid token reference %q: %w" , decodedToken , ErrPointer )
255+ }
267256}
268257
269258func isNil (input any ) bool {
@@ -280,6 +269,14 @@ func isNil(input any) bool {
280269 }
281270}
282271
272+ func typeFromValue (v reflect.Value ) any {
273+ if v .CanAddr () && v .Kind () != reflect .Interface && v .Kind () != reflect .Map && v .Kind () != reflect .Slice && v .Kind () != reflect .Pointer {
274+ return v .Addr ().Interface ()
275+ }
276+
277+ return v .Interface ()
278+ }
279+
283280// GetForToken gets a value for a json pointer token 1 level deep
284281func GetForToken (document any , decodedToken string ) (any , reflect.Kind , error ) {
285282 return getSingleImpl (document , decodedToken , jsonname .DefaultJSONNameProvider )
@@ -352,19 +349,10 @@ func setSingleImpl(node, data any, decodedToken string, nameProvider *jsonname.N
352349 return fmt .Errorf ("cannot set field %q on nil value: %w" , decodedToken , ErrPointer )
353350 }
354351
355- if ns , ok := node .(JSONSetable ); ok { // pointer impl
352+ if ns , ok := node .(JSONSetable ); ok {
356353 return ns .JSONSet (decodedToken , data )
357354 }
358355
359- if rValue .Type ().Implements (jsonSetableType ) {
360- setable , ok := node .(JSONSetable )
361- if ! ok {
362- panic (fmt .Errorf ("internal error: expected a JSONPointable but got %T: %w" , node , ErrPointer ))
363- }
364-
365- return setable .JSONSet (decodedToken , data )
366- }
367-
368356 switch rValue .Kind () { //nolint:exhaustive
369357 case reflect .Struct :
370358 nm , ok := nameProvider .GetGoNameForType (rValue .Type (), decodedToken )
@@ -508,8 +496,8 @@ const (
508496)
509497
510498var (
511- encRefTokReplacer = strings .NewReplacer (encRefTok1 , decRefTok1 , encRefTok0 , decRefTok0 )
512- decRefTokReplacer = strings .NewReplacer (decRefTok1 , encRefTok1 , decRefTok0 , encRefTok0 )
499+ encRefTokReplacer = strings .NewReplacer (encRefTok1 , decRefTok1 , encRefTok0 , decRefTok0 ) //nolint:gochecknoglobals // it's okay to declare a replacer as a private global
500+ decRefTokReplacer = strings .NewReplacer (decRefTok1 , encRefTok1 , decRefTok0 , encRefTok0 ) //nolint:gochecknoglobals // it's okay to declare a replacer as a private global
513501)
514502
515503// Unescape unescapes a json pointer reference token string to the original representation
0 commit comments