Skip to content

Commit

Permalink
Allow negative indexes in DecodePath
Browse files Browse the repository at this point in the history
  • Loading branch information
oschwald committed Sep 22, 2024
1 parent 9826e62 commit 7a7673e
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 11 deletions.
20 changes: 14 additions & 6 deletions decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,21 @@ PATH:
// XXX - use type names in errors.
return fmt.Errorf("expected a slice for %d but found %d", v, typeNum)
}
if size < uint(v) {
// Slice is smaller than index, not found
return nil
var i uint
if v < 0 {
if size < uint(-v) {
// Slice is smaller than negative index, not found
return nil
}
i = size - uint(-v)
} else {
if size <= uint(v) {
// Slice is smaller than index, not found
return nil
}
i = uint(v)
}
// TODO: support negative indexes? Seems useful for subdivisions in
// particular.
offset, err = d.nextValueOffset(offset, uint(v))
offset, err = d.nextValueOffset(offset, i)
if err != nil {
return err
}
Expand Down
30 changes: 26 additions & 4 deletions reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,11 +336,33 @@ func TestDecodePath(t *testing.T) {
require.NoError(t, result.DecodePath(&u, "array", 0))
assert.Equal(t, uint(1), u)

require.NoError(t, result.DecodePath(&u, "array", 2))
assert.Equal(t, uint(3), u)
var u2 uint
require.NoError(t, result.DecodePath(&u2, "array", 2))
assert.Equal(t, uint(3), u2)

require.NoError(t, result.DecodePath(&u, "map", "mapX", "arrayX", 1))
assert.Equal(t, uint(8), u)
// This is past the end of the array
var u3 uint
require.NoError(t, result.DecodePath(&u3, "array", 3))
assert.Equal(t, uint(0), u3)

// Negative offsets

var n1 uint
require.NoError(t, result.DecodePath(&n1, "array", -1))
assert.Equal(t, uint(3), n1)

var n2 uint
require.NoError(t, result.DecodePath(&n2, "array", -3))
assert.Equal(t, uint(1), n2)

var u4 uint
require.NoError(t, result.DecodePath(&u4, "map", "mapX", "arrayX", 1))
assert.Equal(t, uint(8), u4)

// Does key not exist
var ne uint
require.NoError(t, result.DecodePath(&ne, "does-not-exist", 1))
assert.Equal(t, uint(0), ne)
}

type TestInterface interface {
Expand Down
4 changes: 3 additions & 1 deletion result.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ func (r Result) Decode(v any) error {
// value.
//
// For maps, string path elements are used as keys.
// For arrays, int path elements are used as indices.
// For arrays, int path elements are used as indices. A negative offset will
// return values from the end of the array, e.g., -1 will return the last
// element.
//
// If the path is empty, the entire data structure is decoded into v.
//
Expand Down

0 comments on commit 7a7673e

Please sign in to comment.