Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add ArrayIterator to iterate over array values #254

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 81 additions & 4 deletions parser.go
Expand Up @@ -19,6 +19,7 @@ var (
OverflowIntegerError = errors.New("Value is number, but overflowed while parsing")
MalformedStringEscapeError = errors.New("Encountered an invalid escape sequence in a string")
NullValueError = errors.New("Value is null")
DoneError = errors.New("Done. Reached End of Iterator")
)

// How much stack space to allocate for unescaping JSON strings; if a string longer
Expand Down Expand Up @@ -707,12 +708,10 @@ func WriteToBuffer(buffer []byte, str string) int {
}

/*

Del - Receives existing data structure, path to delete.

Returns:
`data` - return modified data

*/
func Delete(data []byte, keys ...string) []byte {
lk := len(keys)
Expand Down Expand Up @@ -793,13 +792,11 @@ func Delete(data []byte, keys ...string) []byte {
}

/*

Set - Receives existing data structure, path to set, and data to set at that key.

Returns:
`value` - modified byte array
`err` - On any parsing error

*/
func Set(data []byte, setValue []byte, keys ...string) (value []byte, err error) {
// ensure keys are set
Expand Down Expand Up @@ -1069,6 +1066,86 @@ func ArrayEach(data []byte, cb func(value []byte, dataType ValueType, offset int
return offset, nil
}

func ArrayIterator(data []byte, keys ...string) (next func() ([]byte, ValueType, int, error), err error) {

makeNextError := func(err error) func() ([]byte, ValueType, int, error) {
return func() ([]byte, ValueType, int, error) { return nil, NotExist, -1, err }
}

if len(data) == 0 {
return makeNextError(MalformedObjectError), MalformedObjectError
}

nT := nextToken(data)
if nT == -1 {
return makeNextError(MalformedJsonError), MalformedJsonError
}

offset := nT + 1

if len(keys) > 0 {
if offset = searchKeys(data, keys...); offset == -1 {
return makeNextError(KeyPathNotFoundError), KeyPathNotFoundError
}

// Go to closest value
nO := nextToken(data[offset:])
if nO == -1 {
return makeNextError(MalformedJsonError), MalformedJsonError
}

offset += nO

if data[offset] != '[' {
return makeNextError(MalformedArrayError), MalformedArrayError
}

offset++
}

isFirst, nextOffset := true, offset

next = func() ([]byte, ValueType, int, error) {
offset = nextOffset

nO := nextToken(data[offset:])
if nO == -1 {
return nil, NotExist, -1, MalformedJsonError
}
offset += nO
if data[offset] == ']' {
return nil, NotExist, -1, DoneError
}

if !isFirst && data[offset] != ',' {
return nil, NotExist, -1, MalformedArrayError
}
if !isFirst {
offset++
}

v, t, o, e := Get(data[offset:])

if e != nil {
return nil, NotExist, -1, e
}

if o == 0 {
return nil, NotExist, -1, DoneError
}

if t == NotExist {
return nil, NotExist, -1, DoneError
}

isFirst = false
nextOffset = offset + o

return v, t, offset - len(v), e
}
return next, nil
}

// ObjectEach iterates over the key-value pairs of a JSON object, invoking a given callback for each such entry
func ObjectEach(data []byte, callback func(key []byte, value []byte, dataType ValueType, offset int) error, keys ...string) (err error) {
offset := 0
Expand Down