jsonenc

package
v0.26.44 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package jsonenc appends JSON to a byte slice: a string literal, an integer, and an object whose members are written in the order they are named. It is a kernel primitive — stdlib-only, and generic down to the signatures: a slice and a value, with no logger, no token and no codec in any of them. It registers no codec and reads no value by reflection; encoding/json stays the codec, and codec/json.Marshal does not change. This package is for the emitters that already write JSON by hand, so that the SDK has one string escaper and not four.

What a string becomes

AppendString writes s between quotes the way encoding/json writes it, with one difference stated after the table:

"  and  \         a backslash before each
\b \f \n \r \t    their short escapes
other < 0x20      \u00XX, lowercase hex
U+2028, U+2029    \u2028, \u2029, as encoding/json does, so that a
                  document pasted into a script is not cut at a line end
invalid UTF-8     each bad byte becomes U+FFFD, written as its three
                  bytes, so the output is always valid UTF-8
everything else   as it is, including DEL (0x7f)

There is NO HTML escaping: '<', '>' and '&' are written as they are, as json.Encoder does after SetEscapeHTML(false) and as json.Marshal does not. A caller that embeds the result in HTML must escape it itself. That is the one difference from json.Marshal, which escapes them as \u003c, \u003e and \u0026, and the fuzz test holds the rest to it: every input decodes to the string json.Marshal's output decodes to, and valid input is byte for byte what a json.Encoder with HTML escaping off writes.

How it is fast

The string is searched a word at a time for the next byte that needs attention — a quote, a backslash, a byte below 0x20 or a byte from 0x80 up — by the first-match search of internal/kernel/swar, and everything before it is copied in one append. A string of ASCII with nothing to escape, which is most of them, costs one search and one copy. A byte from 0x80 up is where the slow path starts: the run of non-ASCII is decoded rune by rune, validated, and copied whole unless it holds a bad byte or a line separator.

Objects

BeginObject opens an object on a slice, and each member method returns the object again, so a call chain reads as the document and writes members in exactly the order it names them: there is no sorting, no map and no duplicate check. A key is escaped like any string. Object.End closes it and returns the slice. An object is a value of two words and allocates nothing; the slice it grows is the caller's.

Cost

Nothing here allocates once the slice has the capacity, and BENCH.md has the figures against encoding/json and the byte loops this replaced.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AppendEscaped

func AppendEscaped(dst []byte, s string) []byte

AppendEscaped appends the body of the JSON string literal of s — what AppendString writes between its quotes — so a caller can join several pieces into one literal, a group prefix and a key, before the closing quote.

func AppendInt

func AppendInt(dst []byte, v int64) []byte

AppendInt appends v to dst in decimal, as a JSON number, and returns the extended slice.

func AppendString

func AppendString(dst []byte, s string) []byte

AppendString appends s to dst as a JSON string literal, quotes included, and returns the extended slice. See the package comment for the exact escapes: invalid UTF-8 becomes U+FFFD, U+2028 and U+2029 are escaped, and '<', '>' and '&' are not.

Example

ExampleAppendString quotes a string with a quote, a newline and a character JavaScript would end a line on.

package main

import (
	"fmt"

	"github.com/kitsunium/sdk/internal/kernel/jsonenc"
)

func main() {
	fmt.Println(string(jsonenc.AppendString(nil, "say \"hi\"\n<b>\u2028")))
}
Output:
"say \"hi\"\n<b>\u2028"

func AppendUint

func AppendUint(dst []byte, v uint64) []byte

AppendUint appends v to dst in decimal, as a JSON number, and returns the extended slice. A value past 2^53 is exact here and is not in a JavaScript reader; write it as a string when the reader is one.

Types

type Object

type Object struct {
	// contains filtered or unexported fields
}

Object is an object being written: the slice so far, and whether a member has been written yet, which decides the comma. It is a value — every method returns the object to carry on with, and the one the caller still holds is stale — and the zero Object is not usable: start with BeginObject.

func BeginObject

func BeginObject(dst []byte) Object

BeginObject appends the opening brace of an object to dst and returns the object that writes its members after it.

Example

ExampleBeginObject writes members in the order they are named.

package main

import (
	"fmt"

	"github.com/kitsunium/sdk/internal/kernel/jsonenc"
)

func main() {
	out := jsonenc.BeginObject(nil).
		String("level", "info").
		Int("n", -7).
		Bool("ok", true).
		Null("err").
		Raw("nested", jsonenc.BeginObject(nil).Uint("id", 9).End()).
		End()
	fmt.Println(string(out))
}
Output:
{"level":"info","n":-7,"ok":true,"err":null,"nested":{"id":9}}

func (Object) Bool

func (o Object) Bool(key string, v bool) Object

Bool writes the member key with the literal true or false.

func (Object) End

func (o Object) End() []byte

End appends the closing brace and returns the slice.

func (Object) Int

func (o Object) Int(key string, v int64) Object

Int writes the member key with the number v.

func (Object) Null

func (o Object) Null(key string) Object

Null writes the member key with the literal null.

func (Object) Raw

func (o Object) Raw(key string, raw []byte) Object

Raw writes the member key with raw, which the caller guarantees is one valid JSON value: it is copied as it is, so a nested object built by another Object, or a number the caller formatted, goes in without a second escape.

func (Object) String

func (o Object) String(key, value string) Object

String writes the member key with the string value, both escaped as AppendString escapes.

func (Object) Uint

func (o Object) Uint(key string, v uint64) Object

Uint writes the member key with the unsigned number v, as AppendUint writes it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL