Documentation
¶
Overview ¶
Package astjson provides fast JSON parsing with optional arena allocation.
Arbitrary JSON may be parsed without creating structs or generating Go code. Just parse JSON and get the required fields with Get* functions.
Heap Mode vs Arena Mode ¶
The library operates in two memory modes depending on whether an arena.Arena is provided:
Heap mode (nil arena): All Value structs and their backing data are allocated on the Go heap. The garbage collector tracks all references normally. Use Parse, ParseBytes, or Parser.Parse / Parser.ParseBytes for this mode. Parsed values remain valid until the next call to any Parse method on the same Parser, or indefinitely when using the package-level convenience functions.
Arena mode (non-nil arena): All Value structs, string backing bytes, and slice backing arrays are allocated on the arena. The Go GC does not scan arena memory, so the library copies all input data onto the arena before parsing. This means the caller can drop references to the input string/bytes immediately after parsing. Parsed values remain valid for the lifetime of the arena. Use ParseWithArena, ParseBytesWithArena, or Parser.ParseWithArena / Parser.ParseBytesWithArena for this mode.
Arena mode is useful for high-throughput parsing where GC pressure from millions of small Value allocations would degrade performance. Instead of creating heap garbage, all allocations go into a contiguous arena buffer that can be reset and reused.
GC Safety Invariant ¶
When using arena mode, the following invariant is maintained automatically:
Arena-allocated Values never reference heap-allocated string data.
This is critical because the GC does not scan arena memory for pointers. If an arena-allocated Value.s field pointed to a heap string's backing array, the GC could collect that string (since it cannot see the reference in arena memory), causing a use-after-free. The library prevents this by:
- Copying the entire input string/bytes onto the arena before parsing, so all parsed substrings (number literals, string values, object keys) point into arena memory.
- Copying string arguments onto the arena in value constructors like StringValue, IntValue, etc.
- Copying object keys onto the arena in Object.Set.
When using heap mode (nil arena), all Values live on the heap where the GC can see them, so heap string references are safe.
Mixing Arena and Heap Values ¶
The noscan property extends beyond string data to all pointer fields within arena-allocated structs. Because arena buffers are raw []byte allocations, the GC does not trace pointer fields such as Value.a ([]*Value), Object.kvs ([]*kv), or kv.v (*Value) that live inside arena memory.
This means storing a heap-allocated *Value into an arena-allocated container is unsafe if no other GC-visible reference to that heap Value exists. The GC may collect the heap Value since it cannot see the reference in arena memory, resulting in a use-after-free.
Affected APIs (when the container is arena-allocated and the value is heap-allocated):
- Object.Set / Value.Set: the value argument is stored directly.
- Value.SetArrayItem: the value argument is stored directly.
- AppendToArray / Value.AppendArrayItems: elements are stored directly.
- MergeValues / MergeValuesWithPath: values from b may be stored in a.
Safe patterns:
- All values from a single arena: always safe.
- All values on the heap (nil arena): always safe.
- Package-level singletons (valueTrue, valueFalse, valueNull, NullValue): always safe because they are GC-visible global variables.
- Using DeepCopy to copy a heap value onto the arena before storing it: always safe because the copy lives entirely in arena memory.
Unsafe pattern:
arenaObj := ObjectValue(a) // arena-allocated heapVal := StringValue(nil, "hello") // heap-allocated arenaObj.Set(a, "key", heapVal) // UNSAFE if heapVal has no other reference heapVal = nil // GC may now collect the heap Value
Safe pattern using DeepCopy:
arenaObj := ObjectValue(a) heapVal := StringValue(nil, "hello") // heap-allocated arenaObj.Set(a, "key", DeepCopy(a, heapVal)) // safe: copy lives in a heapVal = nil // GC collects original, copy is in a
Value Constructors ¶
Use StringValue, IntValue, FloatValue, NumberValue, TrueValue, FalseValue, ObjectValue, and ArrayValue to create new values. These accept an arena.Arena parameter: pass nil for heap allocation or a non-nil arena for arena allocation. All string data is automatically copied onto the arena when a non-nil arena is provided.
Concurrency ¶
Parser, Value, Object, and Scanner cannot be used from concurrent goroutines. Use per-goroutine instances.
Index ¶
- Constants
- Variables
- func AppendToArray(a arena.Arena, array, value *Value)
- func DeduplicateObjectKeysRecursively(v *Value)
- func Exists(data []byte, keys ...string) bool
- func GetBool(data []byte, keys ...string) bool
- func GetBytes(data []byte, keys ...string) []byte
- func GetFloat64(data []byte, keys ...string) float64
- func GetInt(data []byte, keys ...string) int
- func GetString(data []byte, keys ...string) string
- func SetNull(a arena.Arena, v *Value, path ...string)
- func SetValue(a arena.Arena, v *Value, value *Value, path ...string)
- func Validate(s string) error
- func ValidateBytes(b []byte) error
- func ValueIsNonNull(v *Value) bool
- func ValueIsNull(v *Value) bool
- type Object
- type ParseError
- type Parser
- type Scanner
- type Type
- type Value
- func ArrayValue(a arena.Arena) *Value
- func DeepCopy(a arena.Arena, v *Value) *Value
- func FalseValue(a arena.Arena) *Value
- func FloatValue(a arena.Arena, f float64) *Value
- func IntValue(a arena.Arena, i int) *Value
- func MergeValues(ar arena.Arena, a, b *Value) (v *Value, changed bool, err error)
- func MergeValuesWithPath(ar arena.Arena, a, b *Value, path ...string) (v *Value, changed bool, err error)
- func MustParse(s string) *Value
- func MustParseBytes(b []byte) *Value
- func NumberValue(a arena.Arena, s string) *Value
- func ObjectValue(a arena.Arena) *Value
- func Parse(s string) (*Value, error)
- func ParseBytes(b []byte) (*Value, error)
- func ParseBytesWithArena(a arena.Arena, b []byte) (*Value, error)
- func ParseWithArena(a arena.Arena, s string) (*Value, error)
- func StringValue(a arena.Arena, s string) *Value
- func StringValueBytes(a arena.Arena, b []byte) *Value
- func TrueValue(a arena.Arena) *Value
- func (v *Value) AppendArrayItems(a arena.Arena, right *Value)
- func (v *Value) Array() ([]*Value, error)
- func (v *Value) Bool() (bool, error)
- func (v *Value) Del(key string)
- func (v *Value) Exists(keys ...string) bool
- func (v *Value) Float64() (float64, error)
- func (v *Value) Get(keys ...string) *Value
- func (v *Value) GetArray(keys ...string) []*Value
- func (v *Value) GetBool(keys ...string) bool
- func (v *Value) GetFloat64(keys ...string) float64
- func (v *Value) GetInt(keys ...string) int
- func (v *Value) GetInt64(keys ...string) int64
- func (v *Value) GetObject(keys ...string) *Object
- func (v *Value) GetStringBytes(keys ...string) []byte
- func (v *Value) GetUint(keys ...string) uint
- func (v *Value) GetUint64(keys ...string) uint64
- func (v *Value) Int() (int, error)
- func (v *Value) Int64() (int64, error)
- func (v *Value) MarshalTo(dst []byte) []byte
- func (v *Value) Object() (*Object, error)
- func (v *Value) Set(a arena.Arena, key string, value *Value)
- func (v *Value) SetArrayItem(a arena.Arena, idx int, value *Value)
- func (v *Value) String() string
- func (v *Value) StringBytes() ([]byte, error)
- func (v *Value) Type() Type
- func (v *Value) Uint() (uint, error)
- func (v *Value) Uint64() (uint64, error)
Examples ¶
Constants ¶
const MaxDepth = 300
MaxDepth is the maximum depth for nested JSON.
Variables ¶
var ( // ErrMergeDifferentTypes is returned when merging two values of incompatible types. ErrMergeDifferentTypes = errors.New("cannot merge different types") // ErrMergeDifferingArrayLengths is returned when merging arrays of different lengths. ErrMergeDifferingArrayLengths = errors.New("cannot merge arrays of differing lengths") // ErrMergeUnknownType is returned when merging a value with an unrecognized type. ErrMergeUnknownType = errors.New("cannot merge unknown type") )
var (
NullValue = MustParse(`null`)
)
NullValue is a heap-allocated JSON null singleton. It is safe to use from any context (heap or arena) since it is a package-level global that is always reachable by the GC.
Functions ¶
func AppendToArray ¶
AppendToArray appends value to the end of array. Does nothing if array is not of TypeArray. The arena a is used to grow the array's backing slice.
GC safety: when array is arena-allocated (a is non-nil), value must also be arena-allocated from the same arena, or be a package-level singleton. Use DeepCopy on value before calling if value is heap-allocated. See the package documentation section "Mixing Arena and Heap Values".
func DeduplicateObjectKeysRecursively ¶
func DeduplicateObjectKeysRecursively(v *Value)
DeduplicateObjectKeysRecursively removes duplicate object keys from v and all nested objects and arrays, keeping the first occurrence of each key. This modifies v in place and does not require an arena.
func Exists ¶
Exists returns true if the field identified by keys path exists in JSON data.
Array indexes may be represented as decimal numbers in keys.
False is returned on error. Use Parser for proper error handling.
Parser is faster when multiple fields must be checked in the JSON.
Example ¶
package main
import (
"fmt"
"github.com/wundergraph/astjson"
)
func main() {
data := []byte(`{"foo": [1.23,{"bar":33,"baz":null}]}`)
fmt.Printf("exists(data.foo) = %v\n", astjson.Exists(data, "foo"))
fmt.Printf("exists(data.foo[0]) = %v\n", astjson.Exists(data, "foo", "0"))
fmt.Printf("exists(data.foo[1].baz) = %v\n", astjson.Exists(data, "foo", "1", "baz"))
fmt.Printf("exists(data.foobar) = %v\n", astjson.Exists(data, "foobar"))
fmt.Printf("exists(data.foo.bar) = %v\n", astjson.Exists(data, "foo", "bar"))
}
Output: exists(data.foo) = true exists(data.foo[0]) = true exists(data.foo[1].baz) = true exists(data.foobar) = false exists(data.foo.bar) = false
func GetBool ¶
GetBool returns boolean value for the field identified by keys path in JSON data.
Array indexes may be represented as decimal numbers in keys.
False is returned on error. Use Parser for proper error handling.
Parser is faster for obtaining multiple fields from JSON.
func GetBytes ¶
GetBytes returns string value for the field identified by keys path in JSON data.
Array indexes may be represented as decimal numbers in keys.
nil is returned on error. Use Parser for proper error handling.
Parser is faster for obtaining multiple fields from JSON.
func GetFloat64 ¶
GetFloat64 returns float64 value for the field identified by keys path in JSON data.
Array indexes may be represented as decimal numbers in keys.
0 is returned on error. Use Parser for proper error handling.
Parser is faster for obtaining multiple fields from JSON.
func GetInt ¶
GetInt returns int value for the field identified by keys path in JSON data.
Array indexes may be represented as decimal numbers in keys.
0 is returned on error. Use Parser for proper error handling.
Parser is faster for obtaining multiple fields from JSON.
Example ¶
package main
import (
"fmt"
"github.com/wundergraph/astjson"
)
func main() {
data := []byte(`{"foo": [233,true, {"bar": [2343]} ]}`)
n1 := astjson.GetInt(data, "foo", "0")
fmt.Printf("data.foo[0] = %d\n", n1)
n2 := astjson.GetInt(data, "foo", "2", "bar", "0")
fmt.Printf("data.foo[2].bar[0] = %d\n", n2)
}
Output: data.foo[0] = 233 data.foo[2].bar[0] = 2343
func GetString ¶
GetString returns string value for the field identified by keys path in JSON data.
Array indexes may be represented as decimal numbers in keys.
An empty string is returned on error. Use Parser for proper error handling.
Parser is faster for obtaining multiple fields from JSON.
Example ¶
package main
import (
"fmt"
"github.com/wundergraph/astjson"
)
func main() {
data := []byte(`{"foo":{"bar":[123,"baz"]}}`)
s := astjson.GetString(data, "foo", "bar", "1")
fmt.Printf("data.foo.bar[1] = %s", s)
}
Output: data.foo.bar[1] = baz
func SetNull ¶
SetNull sets a null value at the nested key path within v. The null Value is allocated on the arena when a is non-nil. See SetValue for path behavior.
func SetValue ¶
SetValue sets value at the nested key path within v. Intermediate object nodes are created on the arena as needed when they don't exist. The path must have at least one element.
Object keys created along the path are copied onto the arena when a is non-nil, ensuring GC safety. The same arena/heap mixing rules as Object.Set apply to the value argument.
func ValueIsNonNull ¶
ValueIsNonNull reports whether v is non-nil and not TypeNull.
func ValueIsNull ¶
ValueIsNull reports whether v is nil or TypeNull.
Types ¶
type Object ¶
type Object struct {
// contains filtered or unexported fields
}
Object represents JSON object.
Object cannot be used from concurrent goroutines. Use per-goroutine parsers or ParserPool instead.
Cache-friendly layout: hot data first
func (*Object) Del ¶
Del deletes the entry with the given key from o.
Example ¶
package main
import (
"fmt"
"log"
"github.com/wundergraph/astjson"
)
func main() {
v := astjson.MustParse(`{"foo": 123, "bar": [1,2], "baz": "xyz"}`)
o, err := v.Object()
if err != nil {
log.Fatalf("cannot otain object: %s", err)
}
fmt.Printf("%s\n", o)
o.Del("bar")
fmt.Printf("%s\n", o)
o.Del("foo")
fmt.Printf("%s\n", o)
o.Del("baz")
fmt.Printf("%s\n", o)
}
Output: {"foo":123,"bar":[1,2],"baz":"xyz"} {"foo":123,"baz":"xyz"} {"baz":"xyz"} {}
func (*Object) Get ¶
Get returns the value for the given key in the o.
Returns nil if the value for the given key isn't found.
The returned value is valid until Parse is called on the Parser returned o.
func (*Object) Set ¶
Set sets (key, value) entry in the o.
The value must be unchanged during o lifetime.
GC safety: when o is arena-allocated (a is non-nil), value must also be arena-allocated from the same arena, or be a package-level singleton. Storing a heap-allocated *Value in arena memory is unsafe because the GC does not trace pointers within arena buffers. Use DeepCopy to copy a heap-allocated value onto the arena before passing it here. See the package documentation section "Mixing Arena and Heap Values" for details.
func (*Object) String ¶
String returns string representation for the o.
This function is for debugging purposes only. It isn't optimized for speed. See MarshalTo instead.
func (*Object) Visit ¶
Visit calls f for each item in the o in the original order of the parsed JSON.
f cannot hold key and/or v after returning.
Example ¶
package main
import (
"fmt"
"log"
"github.com/wundergraph/astjson"
)
func main() {
s := `{
"obj": { "foo": 1234 },
"arr": [ 23,4, "bar" ],
"str": "foobar"
}`
var p astjson.Parser
v, err := p.Parse(s)
if err != nil {
log.Fatalf("cannot parse json: %s", err)
}
o, err := v.Object()
if err != nil {
log.Fatalf("cannot obtain object from json value: %s", err)
}
o.Visit(func(k []byte, v *astjson.Value) {
switch string(k) {
case "obj":
fmt.Printf("object %s\n", v)
case "arr":
fmt.Printf("array %s\n", v)
case "str":
fmt.Printf("string %s\n", v)
}
})
}
Output: object {"foo":1234} array [23,4,"bar"] string "foobar"
type ParseError ¶
type ParseError struct {
Err error
}
ParseError wraps a JSON parsing error.
func NewParseError ¶
func NewParseError(err error) *ParseError
NewParseError wraps err in a ParseError. Returns nil if err is nil.
func (*ParseError) Error ¶
func (p *ParseError) Error() string
Error returns the error message. Returns an empty string if p is nil.
type Parser ¶
type Parser struct {
}
Parser parses JSON.
Parser may be re-used for subsequent parsing.
Parser supports two allocation modes: heap mode (Parse, ParseBytes) where all values are heap-allocated and GC-managed, and arena mode (ParseWithArena, ParseBytesWithArena) where all values and their backing data are allocated on a caller-provided arena. See the package documentation for details on GC safety.
Parser cannot be used from concurrent goroutines. Use per-goroutine parsers or ParserPool instead.
func (*Parser) Parse ¶
Parse parses s containing JSON.
The returned value is valid until the next call to Parse*.
Use Scanner if a stream of JSON values must be parsed.
Example ¶
package main
import (
"fmt"
"log"
"github.com/wundergraph/astjson"
)
func main() {
var p astjson.Parser
v, err := p.Parse(`{"foo":"bar", "baz": 123}`)
if err != nil {
log.Fatalf("cannot parse json: %s", err)
}
fmt.Printf("foo=%s, baz=%d", v.GetStringBytes("foo"), v.GetInt("baz"))
}
Output: foo=bar, baz=123
Example (Reuse) ¶
package main
import (
"fmt"
"log"
"strconv"
"github.com/wundergraph/astjson"
)
func main() {
var p astjson.Parser
// p may be re-used for parsing multiple json strings.
// This improves parsing speed by reducing the number
// of memory allocations.
//
// Parse call invalidates all the objects previously obtained from p,
// so don't hold these objects after parsing the next json.
for i := 0; i < 3; i++ {
s := fmt.Sprintf(`["foo_%d","bar_%d","%d"]`, i, i, i)
v, err := p.Parse(s)
if err != nil {
log.Fatalf("cannot parse json: %s", err)
}
key := strconv.Itoa(i)
fmt.Printf("a[%d]=%s\n", i, v.GetStringBytes(key))
}
}
Output: a[0]=foo_0 a[1]=bar_1 a[2]=2
func (*Parser) ParseBytes ¶
ParseBytes parses b containing JSON.
The returned Value is valid until the next call to Parse*.
Use Scanner if a stream of JSON values must be parsed.
func (*Parser) ParseBytesWithArena ¶
ParseBytesWithArena parses b containing JSON, allocating all values on the arena.
The input bytes b are copied onto the arena before parsing, so the caller may reuse or discard b immediately after this call returns. All parsed Values, their string data, object keys, and array backing slices live entirely in arena memory, making the result independent of the GC.
The returned value is valid for the lifetime of the arena.
When a is nil, behaves identically to ParseBytes (heap allocation). In that case the caller must not modify b while the returned Value is in use, as it may reference b's underlying memory via zero-copy conversion.
func (*Parser) ParseWithArena ¶
ParseWithArena parses s containing JSON, allocating all values on the arena.
The input string s is copied onto the arena before parsing, so the caller may drop references to s immediately after this call returns. All parsed Values, their string data, object keys, and array backing slices live entirely in arena memory, making the result independent of the GC.
The returned value is valid for the lifetime of the arena.
When a is nil, behaves identically to Parse (heap allocation).
type Scanner ¶
type Scanner struct {
// contains filtered or unexported fields
}
Scanner scans a series of JSON values. Values may be delimited by whitespace.
Scanner may parse JSON lines ( http://jsonlines.org/ ).
Scanner may be re-used for subsequent parsing.
Scanner cannot be used from concurrent goroutines.
Use Parser for parsing only a single JSON value.
Example ¶
package main
import (
"fmt"
"log"
"github.com/wundergraph/astjson"
)
func main() {
var sc astjson.Scanner
sc.Init(` {"foo": "bar" }[ ]
12345"xyz" true false null `)
for sc.Next() {
fmt.Printf("%s\n", sc.Value())
}
if err := sc.Error(); err != nil {
log.Fatalf("unexpected error: %s", err)
}
}
Output: {"foo":"bar"} [] 12345 "xyz" true false null
Example (Reuse) ¶
package main
import (
"fmt"
"log"
"github.com/wundergraph/astjson"
)
func main() {
var sc astjson.Scanner
// The sc may be re-used in order to reduce the number
// of memory allocations.
for i := 0; i < 3; i++ {
s := fmt.Sprintf(`[%d] "%d"`, i, i)
sc.Init(s)
for sc.Next() {
fmt.Printf("%s,", sc.Value())
}
if err := sc.Error(); err != nil {
log.Fatalf("unexpected error: %s", err)
}
fmt.Printf("\n")
}
}
Output: [0],"0", [1],"1", [2],"2",
func (*Scanner) Init ¶
Init initializes sc with the given s.
s may contain multiple JSON values, which may be delimited by whitespace.
func (*Scanner) InitBytes ¶
InitBytes initializes sc with the given b.
b may contain multiple JSON values, which may be delimited by whitespace.
type Type ¶
type Type int
Type represents JSON type.
const ( // TypeNull is JSON null. TypeNull Type = 0 // TypeObject is JSON object type. TypeObject Type = 1 // TypeArray is JSON array type. TypeArray Type = 2 // TypeString is JSON string type. TypeString Type = 3 // TypeNumber is JSON number type. TypeNumber Type = 4 // TypeTrue is JSON true. TypeTrue Type = 5 // TypeFalse is JSON false. TypeFalse Type = 6 )
type Value ¶
type Value struct {
// contains filtered or unexported fields
}
Value represents any JSON value.
Call Type in order to determine the actual type of the JSON value.
Value cannot be used from concurrent goroutines. Use per-goroutine parsers or ParserPool instead.
Cache-friendly layout: hot data first, compact structure
func ArrayValue ¶
ArrayValue creates an empty JSON array Value.
Use Value.SetArrayItem or AppendToArray to add elements. The array's backing slice is grown on the arena when a is non-nil.
When a is nil, the Value is heap-allocated.
func DeepCopy ¶ added in v1.1.0
DeepCopy returns a deep copy of v allocated entirely on arena a. All string data, slice backing arrays, child Values, and object keys are arena-allocated, making the result self-contained within a.
Use DeepCopy when inserting a heap-parsed *Value into an arena-allocated container (via Object.Set, Value.SetArrayItem, [AppendArrayItems], etc.) to prevent the GC from collecting the value while the arena container still references it. Example:
heapVal, _ := Parse(`"hello"`) // heap-allocated arenaObj.Set(a, "key", DeepCopy(a, heapVal)) // safe: copy lives in a
When a is nil (heap mode), DeepCopy returns v unchanged. In heap mode the GC traces all references normally, so no copy is needed.
func FalseValue ¶
FalseValue creates a JSON false Value.
When a is non-nil, the Value struct is allocated on the arena. When a is nil, it is heap-allocated.
func FloatValue ¶
FloatValue creates a JSON number Value from a float64.
When a is non-nil, both the Value struct and the number's string representation are allocated on the arena. When a is nil, the Value is heap-allocated normally.
func IntValue ¶
IntValue creates a JSON number Value from an int.
When a is non-nil, both the Value struct and the number's string representation are allocated on the arena. When a is nil, the Value is heap-allocated normally.
func MergeValues ¶
MergeValues recursively merges b into a and returns the result. For objects, keys from b are added to or replace keys in a. For arrays, elements are merged pairwise (arrays must have equal length). For scalars, b replaces a when the values differ.
The arena ar is used for any new allocations during the merge (new object entries, key copies). Both a and b should have been allocated using the same arena (or both on the heap) to avoid mixing memory lifetimes.
Returns the merged value, whether a was changed, and any error. If a is nil, returns (b, true, nil). If b is nil, returns (a, false, nil).
func MergeValuesWithPath ¶
func MergeValuesWithPath(ar arena.Arena, a, b *Value, path ...string) (v *Value, changed bool, err error)
MergeValuesWithPath wraps b in a nested object structure at the given path, then merges the result into a using MergeValues. For example, with path ["foo", "bar"], b is wrapped as {"foo": {"bar": b}} before merging.
If path is empty, behaves identically to MergeValues.
The arena ar is used for allocating the wrapper objects and during the merge.
func MustParse ¶
MustParse parses json string s.
The function panics if s cannot be parsed. The function is slower than the Parser.Parse for re-used Parser.
func MustParseBytes ¶
MustParseBytes parses b containing json.
The function panics if b cannot be parsed. The function is slower than the Parser.ParseBytes for re-used Parser.
func NumberValue ¶
NumberValue creates a JSON number Value from a raw numeric string.
The string s must be a valid JSON number (e.g. "123", "3.14", "1e10"). No validation is performed.
When a is non-nil, both the Value struct and the string's backing bytes are allocated on the arena (the string is copied). When a is nil, the Value is heap-allocated and references s directly.
func ObjectValue ¶
ObjectValue creates an empty JSON object Value.
Use Object.Set or Value.Set to add entries. Object keys and entry backing slices are allocated on the arena when a is non-nil.
When a is nil, the Value is heap-allocated.
func Parse ¶
Parse parses json string s.
The function is slower than the Parser.Parse for re-used Parser.
func ParseBytes ¶
ParseBytes parses b containing json.
The function is slower than the Parser.ParseBytes for re-used Parser.
func ParseBytesWithArena ¶
ParseBytesWithArena parses b containing json, allocating all values on the arena.
The input bytes are copied onto the arena before parsing, so the caller may reuse or discard b immediately after this call returns. All parsed values live entirely in arena memory and are valid for the arena's lifetime.
When a is nil, behaves identically to ParseBytes (heap allocation). In that case the caller must not modify b while the returned Value is in use.
The function is slower than Parser.ParseBytesWithArena for re-used Parser.
func ParseWithArena ¶
ParseWithArena parses json string s, allocating all values on the arena.
The input string is copied onto the arena before parsing, so the caller may drop references to s immediately after this call returns. All parsed values live entirely in arena memory and are valid for the arena's lifetime.
When a is nil, behaves identically to Parse (heap allocation).
The function is slower than Parser.ParseWithArena for re-used Parser.
func StringValue ¶
StringValue creates a JSON string Value containing s.
When a is non-nil, both the Value struct and the string's backing bytes are allocated on the arena (the string is copied). The caller may drop references to s immediately.
When a is nil, the Value is heap-allocated and references s directly. The caller must keep s reachable for the lifetime of the returned Value.
func StringValueBytes ¶
StringValueBytes creates a JSON string Value from a byte slice.
When a is non-nil, both the Value struct and the bytes are copied onto the arena. The caller may reuse or discard b immediately.
When a is nil, the Value is heap-allocated and references b's underlying memory directly via zero-copy conversion. The caller must not modify b and must keep it reachable for the lifetime of the returned Value.
func TrueValue ¶
TrueValue creates a JSON true Value.
When a is non-nil, the Value struct is allocated on the arena. When a is nil, it is heap-allocated.
func (*Value) AppendArrayItems ¶
AppendArrayItems appends all elements from right into v. Both v and right must be TypeArray; does nothing otherwise. The arena a is used to grow v's backing slice.
GC safety: when v is arena-allocated (a is non-nil), right and its elements must also be arena-allocated from the same arena. Use DeepCopy on right before calling if right is heap-allocated. See the package documentation section "Mixing Arena and Heap Values".
func (*Value) Array ¶
Array returns the underlying JSON array for the v.
The returned array is valid until Parse is called on the Parser returned v.
Use GetArray if you don't need error handling.
func (*Value) Bool ¶
Bool returns the underlying JSON bool for the v.
Use GetBool if you don't need error handling.
func (*Value) Del ¶
Del deletes the entry with the given key from array or object v.
Example ¶
package main
import (
"fmt"
"github.com/wundergraph/astjson"
)
func main() {
v := astjson.MustParse(`{"foo": 123, "bar": [1,2], "baz": "xyz"}`)
fmt.Printf("%s\n", v)
v.Del("foo")
fmt.Printf("%s\n", v)
v.Get("bar").Del("0")
fmt.Printf("%s\n", v)
}
Output: {"foo":123,"bar":[1,2],"baz":"xyz"} {"bar":[1,2],"baz":"xyz"} {"bar":[2],"baz":"xyz"}
func (*Value) Exists ¶
Exists returns true if the field exists for the given keys path.
Array indexes may be represented as decimal numbers in keys.
func (*Value) Float64 ¶
Float64 returns the underlying JSON number for the v.
Use GetFloat64 if you don't need error handling.
func (*Value) Get ¶
Get returns value by the given keys path.
Array indexes may be represented as decimal numbers in keys.
nil is returned for non-existing keys path.
The returned value is valid until Parse is called on the Parser returned v.
Example ¶
package main
import (
"fmt"
"log"
"github.com/wundergraph/astjson"
)
func main() {
s := `{"foo":[{"bar":{"baz":123,"x":"434"},"y":[]},[null, false]],"qwe":true}`
var p astjson.Parser
v, err := p.Parse(s)
if err != nil {
log.Fatalf("cannot parse json: %s", err)
}
vv := v.Get("foo", "0", "bar", "x")
fmt.Printf("foo[0].bar.x=%s\n", vv.GetStringBytes())
vv = v.Get("qwe")
fmt.Printf("qwe=%v\n", vv.GetBool())
vv = v.Get("foo", "1")
fmt.Printf("foo[1]=%s\n", vv)
vv = v.Get("foo").Get("1").Get("1")
fmt.Printf("foo[1][1]=%s\n", vv)
// non-existing key
vv = v.Get("foo").Get("bar").Get("baz", "1234")
fmt.Printf("foo.bar.baz[1234]=%v\n", vv)
}
Output: foo[0].bar.x=434 qwe=true foo[1]=[null,false] foo[1][1]=false foo.bar.baz[1234]=<nil>
func (*Value) GetArray ¶
GetArray returns array value by the given keys path.
Array indexes may be represented as decimal numbers in keys.
nil is returned for non-existing keys path or for invalid value type.
The returned array is valid until Parse is called on the Parser returned v.
func (*Value) GetBool ¶
GetBool returns bool value by the given keys path.
Array indexes may be represented as decimal numbers in keys.
false is returned for non-existing keys path or for invalid value type.
func (*Value) GetFloat64 ¶
GetFloat64 returns float64 value by the given keys path.
Array indexes may be represented as decimal numbers in keys.
0 is returned for non-existing keys path or for invalid value type.
func (*Value) GetInt ¶
GetInt returns int value by the given keys path.
Array indexes may be represented as decimal numbers in keys.
0 is returned for non-existing keys path or for invalid value type.
func (*Value) GetInt64 ¶
GetInt64 returns int64 value by the given keys path.
Array indexes may be represented as decimal numbers in keys.
0 is returned for non-existing keys path or for invalid value type.
func (*Value) GetObject ¶
GetObject returns object value by the given keys path.
Array indexes may be represented as decimal numbers in keys.
nil is returned for non-existing keys path or for invalid value type.
The returned object is valid until Parse is called on the Parser returned v.
func (*Value) GetStringBytes ¶
GetStringBytes returns string value by the given keys path.
Array indexes may be represented as decimal numbers in keys.
nil is returned for non-existing keys path or for invalid value type.
The returned string is valid until Parse is called on the Parser returned v.
Example ¶
package main
import (
"fmt"
"log"
"github.com/wundergraph/astjson"
)
func main() {
s := `[
{"foo": "bar"},
[123, "baz"]
]`
var p astjson.Parser
v, err := p.Parse(s)
if err != nil {
log.Fatalf("cannot parse json: %s", err)
}
fmt.Printf("v[0].foo = %q\n", v.GetStringBytes("0", "foo"))
fmt.Printf("v[1][1] = %q\n", v.GetStringBytes("1", "1"))
fmt.Printf("v[1][0] = %q\n", v.GetStringBytes("1", "0"))
fmt.Printf("v.foo.bar.baz = %q\n", v.GetStringBytes("foo", "bar", "baz"))
}
Output: v[0].foo = "bar" v[1][1] = "baz" v[1][0] = "" v.foo.bar.baz = ""
func (*Value) GetUint ¶
GetUint returns uint value by the given keys path.
Array indexes may be represented as decimal numbers in keys.
0 is returned for non-existing keys path or for invalid value type.
func (*Value) GetUint64 ¶
GetUint64 returns uint64 value by the given keys path.
Array indexes may be represented as decimal numbers in keys.
0 is returned for non-existing keys path or for invalid value type.
func (*Value) Int ¶
Int returns the underlying JSON int for the v.
Use GetInt if you don't need error handling.
func (*Value) Int64 ¶
Int64 returns the underlying JSON int64 for the v.
Use GetInt64 if you don't need error handling.
func (*Value) MarshalTo ¶
MarshalTo appends marshaled v to dst and returns the result.
Example ¶
package main
import (
"fmt"
"log"
"github.com/wundergraph/astjson"
)
func main() {
s := `{
"name": "John",
"items": [
{
"key": "foo",
"value": 123.456,
"arr": [1, "foo"]
},
{
"key": "bar",
"field": [3, 4, 5]
}
]
}`
var p astjson.Parser
v, err := p.Parse(s)
if err != nil {
log.Fatalf("cannot parse json: %s", err)
}
// Marshal items.0 into newly allocated buffer.
buf := v.Get("items", "0").MarshalTo(nil)
fmt.Printf("items.0 = %s\n", buf)
// Re-use buf for marshaling items.1.
buf = v.Get("items", "1").MarshalTo(buf[:0])
fmt.Printf("items.1 = %s\n", buf)
}
Output: items.0 = {"key":"foo","value":123.456,"arr":[1,"foo"]} items.1 = {"key":"bar","field":[3,4,5]}
func (*Value) Object ¶
Object returns the underlying JSON object for the v.
The returned object is valid until Parse is called on the Parser returned v.
Use GetObject if you don't need error handling.
func (*Value) Set ¶
Set sets (key, value) entry in the array or object v.
The value must be unchanged during v lifetime.
Example ¶
v := astjson.MustParse(`{"foo":1,"bar":[2,3]}`)
a := arena.NewMonotonicArena()
// Replace `foo` value with "xyz"
v.Set(a, "foo", astjson.MustParse(`"xyz"`))
// Add "newv":123
v.Set(a, "newv", astjson.MustParse(`123`))
fmt.Printf("%s\n", v)
// Replace `bar.1` with {"x":"y"}
v.Get("bar").Set(a, "1", astjson.MustParse(`{"x":"y"}`))
// Add `bar.3="qwe"
v.Get("bar").Set(a, "3", astjson.MustParse(`"qwe"`))
fmt.Printf("%s\n", v)
Output: {"foo":"xyz","bar":[2,3],"newv":123} {"foo":"xyz","bar":[2,{"x":"y"},null,"qwe"],"newv":123}
func (*Value) SetArrayItem ¶
SetArrayItem sets the value in the array v at idx position.
The value must be unchanged during v lifetime.
GC safety: when v is arena-allocated (a is non-nil), value must also be arena-allocated from the same arena, or be a package-level singleton. Use DeepCopy to copy a heap-allocated value onto the arena before passing it here. See the package documentation section "Mixing Arena and Heap Values".
func (*Value) String ¶
String returns string representation of the v.
The function is for debugging purposes only. It isn't optimized for speed. See MarshalTo instead.
Don't confuse this function with StringBytes, which must be called for obtaining the underlying JSON string for the v.
func (*Value) StringBytes ¶
StringBytes returns the underlying JSON string for the v.
The returned string is valid until Parse is called on the Parser returned v.
Use GetStringBytes if you don't need error handling.
func (*Value) Type ¶
Type returns the type of the v.
Example ¶
package main
import (
"fmt"
"log"
"github.com/wundergraph/astjson"
)
func main() {
s := `{
"object": {},
"array": [],
"string": "foobar",
"number": 123.456,
"true": true,
"false": false,
"null": null
}`
var p astjson.Parser
v, err := p.Parse(s)
if err != nil {
log.Fatalf("cannot parse json: %s", err)
}
fmt.Printf("%s\n", v.Get("object").Type())
fmt.Printf("%s\n", v.Get("array").Type())
fmt.Printf("%s\n", v.Get("string").Type())
fmt.Printf("%s\n", v.Get("number").Type())
fmt.Printf("%s\n", v.Get("true").Type())
fmt.Printf("%s\n", v.Get("false").Type())
fmt.Printf("%s\n", v.Get("null").Type())
}
Output: object array string number true false null