Skip to content

Commit a1150be

Browse files
committed
Added ParsePrimitiveValue convenience function for users
1 parent e6e4e5f commit a1150be

File tree

2 files changed

+188
-84
lines changed

2 files changed

+188
-84
lines changed

parser.go

+40-9
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ import (
1111

1212
// Errors
1313
var (
14-
KeyPathNotFoundError = errors.New("Key path not found")
14+
KeyPathNotFoundError = errors.New("Key path not found")
1515
UnknownValueTypeError = errors.New("Unknown value type")
16-
MalformedJsonError = errors.New("Malformed JSON error")
17-
MalformedStringError = errors.New("Value is string, but can't find closing '\"' symbol")
18-
MalformedArrayError = errors.New("Value is array, but can't find closing ']' symbol")
19-
MalformedObjectError = errors.New("Value looks like object, but can't find closing '}' symbol")
20-
MalformedValueError = errors.New("Value looks like Number/Boolean/None, but can't find its end: ',' or '}' symbol")
16+
MalformedJsonError = errors.New("Malformed JSON error")
17+
MalformedStringError = errors.New("Value is string, but can't find closing '\"' symbol")
18+
MalformedArrayError = errors.New("Value is array, but can't find closing ']' symbol")
19+
MalformedObjectError = errors.New("Value looks like object, but can't find closing '}' symbol")
20+
MalformedValueError = errors.New("Value looks like Number/Boolean/None, but can't find its end: ',' or '}' symbol")
21+
NotAPrimitiveError = errors.New("Cannot parse a non-primitive value in ParsePrimitiveValue")
2122
)
2223

2324
func tokenEnd(data []byte) int {
@@ -31,7 +32,6 @@ func tokenEnd(data []byte) int {
3132
return -1
3233
}
3334

34-
3535
// Find position of next character which is not ' ', ',', '}' or ']'
3636
func nextToken(data []byte, skipComma bool) int {
3737
for i, c := range data {
@@ -133,10 +133,10 @@ func searchKeys(data []byte, keys ...string) int {
133133
i += valueOffset
134134

135135
// if string is a Key, and key level match
136-
if data[i] == ':'{
136+
if data[i] == ':' {
137137
key := unsafeBytesToString(data[keyBegin:keyEnd])
138138

139-
if keyLevel == level-1 && // If key nesting level match current object nested level
139+
if keyLevel == level-1 && // If key nesting level match current object nested level
140140
keys[level-1] == key {
141141
keyLevel++
142142
// If we found all keys in path
@@ -462,3 +462,34 @@ func unsafeBytesToString(data []byte) string {
462462
sh := reflect.StringHeader{Data: h.Data, Len: h.Len}
463463
return *(*string)(unsafe.Pointer(&sh))
464464
}
465+
466+
// ParsePrimitiveValue takes a []byte value returned by Get(), passed to ArrayEach() callback, etc.
467+
// and parses/converts it into a Go type (wrapped in an interface{}) as follows:
468+
//
469+
// Null -> nil
470+
// Boolean -> bool
471+
// String -> string (unescaped)
472+
// Number -> float64
473+
// anything else -> error
474+
//
475+
// This function will likely a memory allocation to return an interface{}, but often user code
476+
// needs an interface{} value, so we provide an efficient implementation for when it is needed.
477+
//
478+
func ParsePrimitiveValue(vbytes []byte, jtype ValueType) (interface{}, error) {
479+
switch jtype {
480+
case Null:
481+
return nil, nil
482+
case Boolean:
483+
return (vbytes[0] == 't'), nil // assumes value is already validated by Get(), etc. since we're given jtype == Boolean
484+
case String:
485+
return string(vbytes), nil // TODO: this does not unescape the string; use unescaper whenever it becomes available
486+
case Number:
487+
if v, err := strconv.ParseFloat(unsafeBytesToString(vbytes), 64); err != nil { // TODO: use better BytesParseFloat in PR #25
488+
return nil, MalformedValueError
489+
} else {
490+
return v, nil
491+
}
492+
default:
493+
return nil, NotAPrimitiveError
494+
}
495+
}

0 commit comments

Comments
 (0)