Skip to content

Commit 2a2f3a2

Browse files
authored
Merge pull request #152 from oschwald/greg/negative-offsets
Allow negative indexes in DecodePath
2 parents 9826e62 + 7a7673e commit 2a2f3a2

File tree

3 files changed

+43
-11
lines changed

3 files changed

+43
-11
lines changed

decoder.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,21 @@ PATH:
147147
// XXX - use type names in errors.
148148
return fmt.Errorf("expected a slice for %d but found %d", v, typeNum)
149149
}
150-
if size < uint(v) {
151-
// Slice is smaller than index, not found
152-
return nil
150+
var i uint
151+
if v < 0 {
152+
if size < uint(-v) {
153+
// Slice is smaller than negative index, not found
154+
return nil
155+
}
156+
i = size - uint(-v)
157+
} else {
158+
if size <= uint(v) {
159+
// Slice is smaller than index, not found
160+
return nil
161+
}
162+
i = uint(v)
153163
}
154-
// TODO: support negative indexes? Seems useful for subdivisions in
155-
// particular.
156-
offset, err = d.nextValueOffset(offset, uint(v))
164+
offset, err = d.nextValueOffset(offset, i)
157165
if err != nil {
158166
return err
159167
}

reader_test.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -336,11 +336,33 @@ func TestDecodePath(t *testing.T) {
336336
require.NoError(t, result.DecodePath(&u, "array", 0))
337337
assert.Equal(t, uint(1), u)
338338

339-
require.NoError(t, result.DecodePath(&u, "array", 2))
340-
assert.Equal(t, uint(3), u)
339+
var u2 uint
340+
require.NoError(t, result.DecodePath(&u2, "array", 2))
341+
assert.Equal(t, uint(3), u2)
341342

342-
require.NoError(t, result.DecodePath(&u, "map", "mapX", "arrayX", 1))
343-
assert.Equal(t, uint(8), u)
343+
// This is past the end of the array
344+
var u3 uint
345+
require.NoError(t, result.DecodePath(&u3, "array", 3))
346+
assert.Equal(t, uint(0), u3)
347+
348+
// Negative offsets
349+
350+
var n1 uint
351+
require.NoError(t, result.DecodePath(&n1, "array", -1))
352+
assert.Equal(t, uint(3), n1)
353+
354+
var n2 uint
355+
require.NoError(t, result.DecodePath(&n2, "array", -3))
356+
assert.Equal(t, uint(1), n2)
357+
358+
var u4 uint
359+
require.NoError(t, result.DecodePath(&u4, "map", "mapX", "arrayX", 1))
360+
assert.Equal(t, uint(8), u4)
361+
362+
// Does key not exist
363+
var ne uint
364+
require.NoError(t, result.DecodePath(&ne, "does-not-exist", 1))
365+
assert.Equal(t, uint(0), ne)
344366
}
345367

346368
type TestInterface interface {

result.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ func (r Result) Decode(v any) error {
6262
// value.
6363
//
6464
// For maps, string path elements are used as keys.
65-
// For arrays, int path elements are used as indices.
65+
// For arrays, int path elements are used as indices. A negative offset will
66+
// return values from the end of the array, e.g., -1 will return the last
67+
// element.
6668
//
6769
// If the path is empty, the entire data structure is decoded into v.
6870
//

0 commit comments

Comments
 (0)