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 alias its backing memory; slices/strings passed to callbacks must not outlive the call (clone via strings.Clone to retain).
Raw JSON value bytes returned by the scanners can be promoted to Go values via DecodeString, DecodeBool, DecodeInt64, DecodeUint64, and DecodeFloat64. Each returns ok=false on malformed input; the integer decoders also reject fractional, exponent, leading '+', and leading-zero forms.
Out-of-scope ¶
jsonfast intentionally omits a generic JSON-to-DOM decoder (map[string]any / []any), a generic any-encoder for Builder, and a whitespace-compacting helper. Fixed-schema callers should use the Iterate* / FindField scanners and the typed Add*Field methods directly. When dynamic data is genuinely required, encode it with encoding/json and splice the result via Builder.AppendRaw or Builder.AddRawJSONField; for whitespace compaction use encoding/json.Compact.
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}