Documentation
¶
Overview ¶
Package jsonfast is a zero-allocation JSON builder and scanner for fixed schemas.
Usage ¶
b := jsonfast.Acquire()
b.BeginObject()
b.AddStringField("message", "hello")
b.AddIntField("severity", 3)
b.AddTimeRFC3339Field("timestamp", time.Now())
b.EndObject()
data := b.Bytes()
jsonfast.Release(b)
Pre-computed keys ¶
var keyMessage = jsonfast.NewFieldKey("message")
b.AddStringFieldKey(keyMessage, "hello")
Field names passed to Add*Field are JSON-escaped on output, so any Go string is safe. NewFieldKey caches the prefix verbatim and therefore requires a safe-ASCII name (printable ASCII excluding '"' and '\\').
Scanning ¶
IterateFields, FindField, IterateArray, IterateStringArray parse JSON structurally without building a DOM. The *String variants take a string input and aliase its backing memory; slices/strings passed to callbacks must not outlive the call (clone via strings.Clone to retain).
NDJSON ¶
BatchWriter appends JSON records separated by '\n' and implements io.Writer (one record per Write) and io.WriterTo.
Index ¶
- func DecodeBool(raw []byte) (value, ok bool)
- func DecodeFloat64(raw []byte) (float64, bool)
- func DecodeInt64(raw []byte) (int64, bool)
- func DecodeString(raw []byte) (string, bool)
- func DecodeUint64(raw []byte) (uint64, bool)
- func EscapeString(s string) string
- func FindField(data []byte, key string) ([]byte, bool)
- func FindFieldString(s, key string) ([]byte, bool)
- func FlattenMap(m map[string]map[string]string, dst map[string]string) map[string]string
- func FlattenObject(b *Builder, data []byte) bool
- func IsStructuralJSON(s string) bool
- func IterateArray(data []byte, fn func(element []byte) bool) bool
- func IterateArrayString(s string, fn func(element []byte) bool) bool
- func IterateFields(data []byte, fn func(key, value []byte) bool) bool
- func IterateFieldsString(s string, fn func(key, value []byte) bool) bool
- func IterateStringArray(data []byte, fn func(val string) bool) bool
- func IterateStringArrayString(s string, fn func(val string) bool) bool
- func Release(b *Builder)
- func ReleaseBatchWriter(bw *BatchWriter)
- func SkipBracedAt(data []byte, i int, opener, closer byte) (int, bool)
- func SkipStringAt(data []byte, i int) (int, bool)
- func SkipValueAt(data []byte, i int) (int, bool)
- func SkipWS(data []byte, i int) int
- func WarmBatchWriterPool(n int)
- func WarmPool(n int)
- type BatchWriter
- func (w *BatchWriter) Append(record []byte)
- func (w *BatchWriter) AppendString(record string)
- func (w *BatchWriter) Bytes() []byte
- func (w *BatchWriter) Count() int
- func (w *BatchWriter) Grow(n int)
- func (w *BatchWriter) Len() int
- func (w *BatchWriter) Reset()
- func (w *BatchWriter) Write(p []byte) (int, error)
- func (w *BatchWriter) WriteTo(target io.Writer) (int64, error)
- type Builder
- func (b *Builder) AddBoolField(name string, v bool)
- func (b *Builder) AddBoolFieldKey(k FieldKey, v bool)
- func (b *Builder) AddFlattenedMapField(m map[string]map[string]string)
- func (b *Builder) AddFloat64Field(name string, v float64)
- func (b *Builder) AddFloat64FieldKey(k FieldKey, v float64)
- func (b *Builder) AddInt64Field(name string, v int64)
- func (b *Builder) AddInt64FieldKey(k FieldKey, v int64)
- func (b *Builder) AddIntField(name string, v int)
- func (b *Builder) AddIntFieldKey(k FieldKey, v int)
- func (b *Builder) AddNestedStringMapField(name string, m map[string]map[string]string)
- func (b *Builder) AddNullField(name string)
- func (b *Builder) AddNullFieldKey(k FieldKey)
- func (b *Builder) AddRawBytesField(name, value []byte)
- func (b *Builder) AddRawJSONField(name string, rawJSON []byte)
- func (b *Builder) AddRawJSONFieldKey(k FieldKey, rawJSON []byte)
- func (b *Builder) AddStringArrayField(name string, values []string)
- func (b *Builder) AddStringArrayFieldKey(k FieldKey, values []string)
- func (b *Builder) AddStringField(name, value string)
- func (b *Builder) AddStringFieldKey(k FieldKey, value string)
- func (b *Builder) AddStringMapObject(m map[string]string, rawJSONKey string)
- func (b *Builder) AddStringMapObjectField(name string, m map[string]string, rawJSONKey string)
- func (b *Builder) AddTimeRFC3339Field(name string, t time.Time)
- func (b *Builder) AddTimeRFC3339FieldKey(k FieldKey, t time.Time)
- func (b *Builder) AddTimeRFC3339OffsetField(name string, t time.Time)
- func (b *Builder) AddTimeRFC3339OffsetFieldKey(k FieldKey, t time.Time)
- func (b *Builder) AddUint64FieldKey(k FieldKey, v uint64)
- func (b *Builder) AppendEscapedString(s string)
- func (b *Builder) AppendRaw(p []byte)
- func (b *Builder) AppendRawString(s string)
- func (b *Builder) BeginObject()
- func (b *Builder) BeginObjectField(name string)
- func (b *Builder) BeginObjectFieldKey(k FieldKey)
- func (b *Builder) Bytes() []byte
- func (b *Builder) EndObject()
- func (b *Builder) EndObjectField()
- func (b *Builder) Grow(n int)
- func (b *Builder) Len() int
- func (b *Builder) Reset()
- func (b *Builder) Write(p []byte) (int, error)
- func (b *Builder) WriteTo(w io.Writer) (int64, error)
- type FieldKey
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DecodeBool ¶ added in v0.2.0
DecodeBool decodes "true" or "false".
func DecodeFloat64 ¶ added in v0.2.0
DecodeFloat64 decodes any RFC 8259 number into a float64. NaN and Inf are rejected.
func DecodeInt64 ¶ added in v0.2.0
DecodeInt64 decodes a JSON integer. Rejects fractional forms, exponents, leading '+' and leading zeros (except "0" and "-0").
func DecodeString ¶ added in v0.2.0
DecodeString decodes a JSON string (including surrounding quotes) into its Go form. The returned string is a fresh allocation.
func DecodeUint64 ¶ added in v0.2.0
DecodeUint64 decodes a non-negative JSON integer. Same rejection rules as DecodeInt64.
func EscapeString ¶
EscapeString returns s with JSON escaping. If s is already safe ASCII it is returned unchanged (zero allocation). Invalid UTF-8 bytes are replaced with U+FFFD.
Example ¶
package main
import (
"fmt"
"github.com/ubyte-source/go-jsonfast"
)
func main() {
escaped := jsonfast.EscapeString(`She said "hello" and left`)
fmt.Println(escaped)
}
Output: She said \"hello\" and left
func FindField ¶
FindField returns the raw value bytes for the first top-level field matching key, or (nil, false) if not found. Keys with JSON escape sequences are decoded on the fly.
Example ¶
package main
import (
"fmt"
"github.com/ubyte-source/go-jsonfast"
)
func main() {
data := []byte(`{"hostname":"fw01","severity":4,"message":"ok"}`)
if val, ok := jsonfast.FindField(data, "severity"); ok {
fmt.Printf("severity=%s\n", val)
}
}
Output: severity=4
func FindFieldString ¶ added in v0.0.2
FindFieldString is FindField with a string input. The returned slice aliases s and must not be mutated.
func FlattenMap ¶
FlattenMap flattens a nested map into outer.inner → value form. If dst is nil a new map is allocated sized to the total entry count.
Example ¶
package main
import (
"fmt"
"github.com/ubyte-source/go-jsonfast"
)
func main() {
m := map[string]map[string]string{
"host": {"name": "fw01", "ip": "10.0.0.1"},
}
flat := jsonfast.FlattenMap(m, nil)
fmt.Println(flat["host.name"])
fmt.Println(flat["host.ip"])
}
Output: fw01 10.0.0.1
func FlattenObject ¶
FlattenObject recursively flattens a JSON object's leaves into b (up to 64 levels deep). Non-object input is skipped silently.
func IsStructuralJSON ¶ added in v0.1.0
IsStructuralJSON reports whether s is a grammar-valid JSON object or array (every nested value checked) with no trailing content. Duplicate keys are not rejected; invalid UTF-8 bytes are passed through.
Example ¶
package main
import (
"fmt"
"github.com/ubyte-source/go-jsonfast"
)
func main() {
fmt.Println(jsonfast.IsStructuralJSON(`{"key":"value"}`))
fmt.Println(jsonfast.IsStructuralJSON(`not json`))
fmt.Println(jsonfast.IsStructuralJSON(`{not json}`))
}
Output: true false false
func IterateArray ¶ added in v0.0.2
IterateArray calls fn for each element. element is the raw JSON bytes of the value.
func IterateArrayString ¶ added in v0.0.2
IterateArrayString is IterateArray with a string input.
func IterateFields ¶
IterateFields calls fn for each top-level field. key includes the surrounding quotes; value is the raw JSON bytes.
func IterateFieldsString ¶
IterateFieldsString is IterateFields with a string input. The slices passed to fn alias s and must not be mutated.
func IterateStringArray ¶ added in v0.0.2
IterateStringArray calls fn for each string element. val aliases the input and is only valid for the duration of the callback; use strings.Clone to retain. Non-string elements abort the iteration.
func IterateStringArrayString ¶ added in v0.0.2
IterateStringArrayString is IterateStringArray with a string input.
func Release ¶
func Release(b *Builder)
Release returns b to the pool. Buffers larger than 256 KB are discarded.
func ReleaseBatchWriter ¶
func ReleaseBatchWriter(bw *BatchWriter)
ReleaseBatchWriter returns bw to the pool. Buffers larger than 4 MB are discarded.
func SkipBracedAt ¶
SkipBracedAt skips a balanced opener/closer pair starting at data[i].
func SkipStringAt ¶
SkipStringAt skips a JSON string starting at data[i] (which must be '"') and returns the index past the closing quote. Raw control bytes (< 0x20) are rejected.
func SkipValueAt ¶
SkipValueAt skips one JSON value starting at data[i] and returns the index past it.
func WarmBatchWriterPool ¶ added in v0.1.0
func WarmBatchWriterPool(n int)
WarmBatchWriterPool pre-allocates n BatchWriters and returns them to the pool.
func WarmPool ¶ added in v0.1.0
func WarmPool(n int)
WarmPool pre-allocates n Builders and returns them to the pool.
Example ¶
package main
import (
"fmt"
"github.com/ubyte-source/go-jsonfast"
)
func main() {
jsonfast.WarmPool(128)
b := jsonfast.Acquire()
b.BeginObject()
b.AddStringField("warmed", "yes")
b.EndObject()
fmt.Println(string(b.Bytes()))
jsonfast.Release(b)
}
Output: {"warmed":"yes"}
Types ¶
type BatchWriter ¶
type BatchWriter struct {
// contains filtered or unexported fields
}
BatchWriter accumulates newline-delimited JSON records. Not safe for concurrent use.
Example ¶
package main
import (
"fmt"
"github.com/ubyte-source/go-jsonfast"
)
func main() {
bw := jsonfast.NewBatchWriter(256)
bw.Append([]byte(`{"line":1}`))
bw.Append([]byte(`{"line":2}`))
fmt.Print(string(bw.Bytes()))
}
Output: {"line":1} {"line":2}
func AcquireBatchWriter ¶
func AcquireBatchWriter() *BatchWriter
AcquireBatchWriter returns a BatchWriter from the pool.
Example ¶
package main
import (
"fmt"
"github.com/ubyte-source/go-jsonfast"
)
func main() {
bw := jsonfast.AcquireBatchWriter()
defer jsonfast.ReleaseBatchWriter(bw)
bw.Append([]byte(`{"pooled":true}`))
fmt.Print(string(bw.Bytes()))
}
Output: {"pooled":true}
func NewBatchWriter ¶
func NewBatchWriter(capacity int) *BatchWriter
NewBatchWriter returns a BatchWriter with the given initial capacity. Non-positive capacities are clamped to 4096.
func (*BatchWriter) Append ¶
func (w *BatchWriter) Append(record []byte)
Append writes record followed by '\n'.
func (*BatchWriter) AppendString ¶
func (w *BatchWriter) AppendString(record string)
AppendString writes record followed by '\n'.
func (*BatchWriter) Bytes ¶
func (w *BatchWriter) Bytes() []byte
Bytes returns the accumulated payload. The slice aliases the internal buffer.
func (*BatchWriter) Count ¶
func (w *BatchWriter) Count() int
Count returns the number of records in the batch.
func (*BatchWriter) Grow ¶
func (w *BatchWriter) Grow(n int)
Grow ensures at least n bytes of spare capacity.
func (*BatchWriter) Reset ¶
func (w *BatchWriter) Reset()
Reset clears the batch contents while retaining the backing array.
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder appends JSON into a reusable byte slice. Not safe for concurrent use.
Example ¶
package main
import (
"fmt"
"github.com/ubyte-source/go-jsonfast"
)
func main() {
b := jsonfast.New(256)
b.BeginObject()
b.AddStringField("message", "Hello, World!")
b.AddIntField("severity", 5)
b.AddBoolField("active", true)
b.EndObject()
fmt.Println(string(b.Bytes()))
}
Output: {"message":"Hello, World!","severity":5,"active":true}
Example (WithTimestamp) ¶
package main
import (
"fmt"
"time"
"github.com/ubyte-source/go-jsonfast"
)
func main() {
b := jsonfast.New(256)
ts := time.Date(2024, 3, 15, 14, 30, 45, 0, time.UTC)
b.BeginObject()
b.AddStringField("msg", "test")
b.AddTimeRFC3339Field("ts", ts)
b.EndObject()
fmt.Println(string(b.Bytes()))
}
Output: {"msg":"test","ts":"2024-03-15T14:30:45Z"}
func Acquire ¶
func Acquire() *Builder
Acquire returns a Builder from the pool, ready for use.
Example ¶
package main
import (
"fmt"
"github.com/ubyte-source/go-jsonfast"
)
func main() {
b := jsonfast.Acquire()
defer jsonfast.Release(b)
b.BeginObject()
b.AddStringField("source", "pool")
b.EndObject()
fmt.Println(string(b.Bytes()))
}
Output: {"source":"pool"}
func New ¶
New returns a Builder with the given initial capacity. Non-positive capacities are clamped to 256.
func (*Builder) AddBoolField ¶
AddBoolField adds "name":true or "name":false.
func (*Builder) AddBoolFieldKey ¶
AddBoolFieldKey adds "name":true or "name":false using a pre-computed key.
func (*Builder) AddFlattenedMapField ¶
AddFlattenedMapField emits nested map data as sorted "outer.inner":"value" fields into the current object. Up to 16 total entries fit in a stack buffer; larger maps allocate once.
func (*Builder) AddFloat64Field ¶
AddFloat64Field adds "name":<float64>. NaN and ±Inf are emitted as null.
Example ¶
package main
import (
"fmt"
"github.com/ubyte-source/go-jsonfast"
)
func main() {
b := jsonfast.New(64)
b.BeginObject()
b.AddFloat64Field("pi", 3.14159)
b.EndObject()
fmt.Println(string(b.Bytes()))
}
Output: {"pi":3.14159}
func (*Builder) AddFloat64FieldKey ¶
AddFloat64FieldKey adds "name":<float64> using a pre-computed key.
func (*Builder) AddInt64Field ¶
AddInt64Field adds "name":<int64>.
func (*Builder) AddInt64FieldKey ¶
AddInt64FieldKey adds "name":<int64> using a pre-computed key.
func (*Builder) AddIntField ¶
AddIntField adds "name":<int>.
func (*Builder) AddIntFieldKey ¶
AddIntFieldKey adds "name":<int> using a pre-computed key.
func (*Builder) AddNestedStringMapField ¶
AddNestedStringMapField adds "name":{outer:{inner:"v"}}, keys sorted at both levels.
func (*Builder) AddNullField ¶
AddNullField adds "name":null.
func (*Builder) AddNullFieldKey ¶
AddNullFieldKey adds "name":null using a pre-computed key.
func (*Builder) AddRawBytesField ¶
AddRawBytesField adds "name":<value> where name and value are copied verbatim.
func (*Builder) AddRawJSONField ¶
AddRawJSONField adds "name":<raw> without escaping. rawJSON must be well-formed JSON.
func (*Builder) AddRawJSONFieldKey ¶
AddRawJSONFieldKey adds "name":<raw> using a pre-computed key.
func (*Builder) AddStringArrayField ¶ added in v0.2.0
AddStringArrayField adds "name":["v1","v2",...] with value escaping.
func (*Builder) AddStringArrayFieldKey ¶ added in v0.2.0
AddStringArrayFieldKey adds "name":["v1",...] using a pre-computed key.
func (*Builder) AddStringField ¶
AddStringField adds "name":"value" with value escaping.
func (*Builder) AddStringFieldKey ¶
AddStringFieldKey adds "name":"value" using a pre-computed key.
func (*Builder) AddStringMapObject ¶
AddStringMapObject writes m as a standalone JSON object (no name, no leading comma). Keys are sorted. If rawJSONKey is non-empty, values for that key are embedded as raw JSON when IsStructuralJSON accepts them.
func (*Builder) AddStringMapObjectField ¶ added in v0.2.0
AddStringMapObjectField adds "name":{...} with m encoded as a JSON object. Semantics match AddStringMapObject.
func (*Builder) AddTimeRFC3339Field ¶
AddTimeRFC3339Field adds "name":"<RFC3339>" in UTC. Years are clamped to [0, 9999]; pre-epoch timestamps are clamped to the epoch.
func (*Builder) AddTimeRFC3339FieldKey ¶
AddTimeRFC3339FieldKey adds "name":"<RFC3339>" in UTC using a pre-computed key.
func (*Builder) AddTimeRFC3339OffsetField ¶ added in v0.2.0
AddTimeRFC3339OffsetField adds "name":"<RFC3339>" preserving the input timezone offset (Z, +HH:MM, or -HH:MM).
func (*Builder) AddTimeRFC3339OffsetFieldKey ¶ added in v0.2.0
AddTimeRFC3339OffsetFieldKey adds "name":"<RFC3339>" preserving the timezone offset, using a pre-computed key.
func (*Builder) AddUint64FieldKey ¶
AddUint64FieldKey adds "name":<uint64> using a pre-computed key.
func (*Builder) AppendEscapedString ¶
AppendEscapedString appends s with JSON escaping (no surrounding quotes).
func (*Builder) AppendRawString ¶
AppendRawString appends a raw string.
func (*Builder) BeginObject ¶
func (b *Builder) BeginObject()
BeginObject writes '{' and resets the field separator state.
func (*Builder) BeginObjectField ¶ added in v0.2.0
BeginObjectField opens a nested object as "name":{, ready for inner Add*Field calls. Pair with EndObjectField.
func (*Builder) BeginObjectFieldKey ¶ added in v0.2.0
BeginObjectFieldKey opens a nested object with a pre-computed key.
func (*Builder) Bytes ¶
Bytes returns the accumulated bytes. The slice aliases the internal buffer and must not be used after Reset or Release.
func (*Builder) EndObjectField ¶ added in v0.2.0
func (b *Builder) EndObjectField()
EndObjectField closes a nested object opened by BeginObjectField or BeginObjectFieldKey and restores the outer separator state.
func (*Builder) Grow ¶
Grow ensures at least n bytes of spare capacity.
Example ¶
package main
import (
"fmt"
"github.com/ubyte-source/go-jsonfast"
)
func main() {
b := jsonfast.New(16)
b.Grow(1024)
b.BeginObject()
b.AddStringField("k", "v")
b.EndObject()
fmt.Println(string(b.Bytes()))
}
Output: {"k":"v"}
func (*Builder) Reset ¶
func (b *Builder) Reset()
Reset clears the buffer contents while retaining the backing array.
type FieldKey ¶
type FieldKey string
FieldKey is a pre-computed field prefix in the form `,"name":`.
func NewFieldKey ¶
NewFieldKey returns a FieldKey for the given safe-ASCII name.
Example ¶
package main
import (
"fmt"
"github.com/ubyte-source/go-jsonfast"
)
func main() {
var keyLevel = jsonfast.NewFieldKey("level")
b := jsonfast.New(64)
b.BeginObject()
b.AddIntFieldKey(keyLevel, 3)
b.EndObject()
fmt.Println(string(b.Bytes()))
}
Output: {"level":3}