@@ -20,21 +20,16 @@ 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 {
31- JSONLookup (string ) (any , error )
26+ JSONLookup (key string ) (any , error )
3227}
3328
3429// JSONSetable is an interface for structs to implement when they need to customize the
3530// json pointer process
3631type JSONSetable interface {
37- JSONSet (string , any ) error
32+ JSONSet (key string , value any ) error
3833}
3934
4035// Pointer is a representation of a json pointer
@@ -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 }
@@ -185,81 +180,79 @@ func (p *Pointer) set(node, data any, nameProvider *jsonname.NameProvider) error
185180 decodedToken := Unescape (token )
186181
187182 if isLastToken {
188-
189183 return setSingleImpl (node , data , decodedToken , nameProvider )
190184 }
191185
192- // Check for nil during traversal
193- if isNil ( node ) {
194- 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
195189 }
196190
197- rValue := reflect . Indirect ( reflect . ValueOf ( node ))
198- kind := rValue . Kind ()
191+ node = next
192+ }
199193
200- if rValue .Type ().Implements (jsonPointableType ) {
201- r , err := node .(JSONPointable ).JSONLookup (decodedToken )
202- if err != nil {
203- return err
204- }
205- fld := reflect .ValueOf (r )
206- if fld .CanAddr () && fld .Kind () != reflect .Interface && fld .Kind () != reflect .Map && fld .Kind () != reflect .Slice && fld .Kind () != reflect .Pointer {
207- node = fld .Addr ().Interface ()
208- continue
209- }
210- node = r
211- continue
194+ return nil
195+ }
196+
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
212208 }
213209
214- switch kind { //nolint:exhaustive
215- case reflect .Struct :
216- nm , ok := nameProvider .GetGoNameForType (rValue .Type (), decodedToken )
217- if ! ok {
218- return fmt .Errorf ("object has no field %q: %w" , decodedToken , ErrPointer )
219- }
220- fld := rValue .FieldByName (nm )
221- if fld .CanAddr () && fld .Kind () != reflect .Interface && fld .Kind () != reflect .Map && fld .Kind () != reflect .Slice && fld .Kind () != reflect .Pointer {
222- node = fld .Addr ().Interface ()
223- continue
224- }
225- 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+ }
226214
227- case reflect .Map :
228- kv := reflect .ValueOf (decodedToken )
229- mv := rValue .MapIndex (kv )
215+ return r , nil
216+ }
230217
231- if ! mv .IsValid () {
232- return fmt .Errorf ("object has no key %q: %w" , decodedToken , ErrPointer )
233- }
234- if mv .CanAddr () && mv .Kind () != reflect .Interface && mv .Kind () != reflect .Map && mv .Kind () != reflect .Slice && mv .Kind () != reflect .Pointer {
235- node = mv .Addr ().Interface ()
236- continue
237- }
238- node = mv .Interface ()
218+ rValue := reflect .Indirect (reflect .ValueOf (node ))
219+ kind := rValue .Kind ()
239220
240- case reflect .Slice :
241- tokenIndex , err := strconv .Atoi (decodedToken )
242- if err != nil {
243- return err
244- }
245- sLength := rValue .Len ()
246- if tokenIndex < 0 || tokenIndex >= sLength {
247- return fmt .Errorf ("index out of bounds array[0,%d] index '%d': %w" , sLength , tokenIndex , ErrPointer )
248- }
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+ }
249227
250- elem := rValue .Index (tokenIndex )
251- if elem .CanAddr () && elem .Kind () != reflect .Interface && elem .Kind () != reflect .Map && elem .Kind () != reflect .Slice && elem .Kind () != reflect .Pointer {
252- node = elem .Addr ().Interface ()
253- continue
254- }
255- node = elem .Interface ()
228+ return typeFromValue (rValue .FieldByName (nm )), nil
256229
257- default :
258- 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 )
259236 }
260- }
261237
262- 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+ }
263256}
264257
265258func isNil (input any ) bool {
@@ -276,6 +269,14 @@ func isNil(input any) bool {
276269 }
277270}
278271
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+
279280// GetForToken gets a value for a json pointer token 1 level deep
280281func GetForToken (document any , decodedToken string ) (any , reflect.Kind , error ) {
281282 return getSingleImpl (document , decodedToken , jsonname .DefaultJSONNameProvider )
@@ -348,14 +349,10 @@ func setSingleImpl(node, data any, decodedToken string, nameProvider *jsonname.N
348349 return fmt .Errorf ("cannot set field %q on nil value: %w" , decodedToken , ErrPointer )
349350 }
350351
351- if ns , ok := node .(JSONSetable ); ok { // pointer impl
352+ if ns , ok := node .(JSONSetable ); ok {
352353 return ns .JSONSet (decodedToken , data )
353354 }
354355
355- if rValue .Type ().Implements (jsonSetableType ) {
356- return node .(JSONSetable ).JSONSet (decodedToken , data )
357- }
358-
359356 switch rValue .Kind () { //nolint:exhaustive
360357 case reflect .Struct :
361358 nm , ok := nameProvider .GetGoNameForType (rValue .Type (), decodedToken )
@@ -499,8 +496,8 @@ const (
499496)
500497
501498var (
502- encRefTokReplacer = strings .NewReplacer (encRefTok1 , decRefTok1 , encRefTok0 , decRefTok0 )
503- 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
504501)
505502
506503// Unescape unescapes a json pointer reference token string to the original representation
0 commit comments