Skip to content

json2 #

json2 replaces the removed cJSON based json module. v fmt -w file.v
rewrites the usual json.decode(T, s), json.encode(x) and
json.encode_pretty(x) calls to json2, and leaves code it cannot rewrite
safely unchanged. By hand:

  • json.decode(T, s) becomes json2.decode[T](s)
  • json.encode(x) becomes json2.encode(x, escape_unicode: true, time_as_unix: true)
  • json.encode_pretty(x) becomes json2.encode(x, prettify: true, legacy_layout: true, escape_unicode: true, time_as_unix: true)

These options keep the output of the old module: non-ASCII characters escaped as
\uXXXX, time.Time values as Unix timestamps, and its tab based pretty layout.
One difference remains: a @[raw] field, or a string that receives a JSON object
or array, holds the JSON text exactly as written, while the old module returned it
without whitespace.

json.decode(?T, s) has no direct counterpart, since V does not accept ?T as a
type argument, and vfmt leaves such files unchanged: decode T with
json2.decode[T](s), and handle a null input yourself.

json.encode(x) wrote a sum type value narrowed by x is Cat or match x as the
whole sum type, with its _type field, while json2.encode(x) writes the narrowed
variant. vfmt leaves such files unchanged as well: cast the value back to its sum
type, as in json2.encode(Animal(x), escape_unicode: true, time_as_unix: true).

A type with its own to_json() method (or the deprecated json_str()), such as
big.Integer, is written by json2.encode through that method, while the old module
ignored it and wrote the type's fields. vfmt migrates these calls too, since it does
not resolve types, so check the output of such types after migrating. Decoding is not
affected: the from_json_* methods only handle a JSON string, number, boolean or
null, so objects written by the old module still decode field by field.

json2.decode also accepts an enum value given as the number of one of its members,
for an enum without @[json_as_number] too, as json2.encode(x, enum_as_int: true)
writes it; the old module only accepted the member's name there. Other numbers are
still rejected.

json2 is an experimental JSON parser written from scratch on V.

Aliases of Any decode through the selected concrete variant, including at the root of a JSON value or as array and map elements.

Typed map keys

Integer map keys are parsed as the declared integer type with range checks. Invalid numeric text and values outside that type's range return errors, including with the default decoding options. For example, decoding {"256":1} as map[u8]int fails.

A rune map key is a string containing exactly one Unicode character. Encoding and decoding preserve that character, including non-ASCII keys. Code that used numeric text such as "65" for the code point of A should use "A" instead. A digit key such as "1" means the character 1; empty and multi-character keys are rejected. json2.decode[map[rune]int](json2.encode(values)) round-trips the rune keys.

Nesting depth limit

Standard decoding accepts container nesting up to 512 array/object levels in a document. Deeper parse, decode[T] or decode_reuse[T] input returns a bounded error instead of recursing to a stack overflow. The limit is implemented for standard JSON only: the json5: true option uses its own parser (vlib/json2/json5_decode.v), whose depth handling is not covered by this limit.

JSON5

Set json5: true on the existing encoding or decoding options to use JSON5:

import json2

struct Config {
    name string @[json: 'displayName']
    port int = 8080
}

fn main() {
    cfg := json2.decode[Config]("{displayName: 'V', port: 0x1F90,}", json5: true)!
    text := json2.encode(cfg,
        json5:           true
        single_quotes:   true
        unquoted_keys:   true
        trailing_commas: true
        prettify:        true
        indent_string:   '  '
    )
    println(text)
}

JSON5 decoding accepts comments, bare object keys (including \uXXXX escapes), single quotes, trailing commas, hexadecimal numbers, leading +, leading or trailing decimal points, Infinity and NaN. Strings support JSON5 escapes and escaped line continuations, including UTF-16 surrogate pairs. Malformed escapes return a JsonScanError with a line and column. Decimal integer parts cannot have leading zeros: 01 and 00.5 are rejected. Bare keys follow ECMAScript IdentifierName categories using Unicode 15.0.0: letters (Lu, Ll, Lt, Lm, Lo, Nl), $ and _ may start a key; Mn and Mc marks, Nd decimal digits, Pc connectors, U+200C and U+200D may also continue it. Other numbers (No) and enclosing marks (Me) require quoted keys. Numeric literal keys such as {42: 1} and {0x10: 1} are rejected; quote the keys instead. Bare null, true, false, Infinity and NaN are valid identifier keys, while signed forms such as +Infinity and -NaN require quotes. All Unicode space separators are accepted between tokens, including U+1680 and U+2000. Escaped digits \1 through \9 are rejected, and \0 cannot precede another decimal digit. Typed decoding errors report their location and context in the original JSON5 input. Columns count Unicode code points, excluding an initial BOM; tabs occupy eight columns. Error previews keep complete runes, limit their prefix and highlighted span to 50 columns, and expand tabs to spaces so the underline aligns with the displayed text. CR, LF, CRLF, U+2028 and U+2029 are counted as JSON5 line terminators. Raw LF and CR in strings are rejected; use a backslash line continuation or a string escape. Unescaped U+2028 and U+2029 are allowed in strings, as specified by JSON5 section 5.2. Decoded strings, raw fields and retained scalar-hook inputs own their text in both dialects. File contents, normalized decoding buffers and decode_any serialization buffers are released after decoding; returned values remain valid independently of those buffers.

single_quotes, unquoted_keys and trailing_commas only affect encoding when json5: true. Otherwise the existing JSON output is unchanged. Bare keys are used only for valid identifiers; other keys are quoted and escaped. prettify, indent_string, newline_string, escape_unicode and the other encoding options work in either dialect. Trailing commas also work in compact output. JSON5 strings escape U+2028 and U+2029 with either quote style, even without escape_unicode.

JSON5 encodes non-finite floats as Infinity, -Infinity and NaN; ordinary JSON continues to encode them as null. Typed integer decoding preserves 64-bit values, including hexadecimal integers, and rejects values outside the target's range. Floating-point decoding accepts hexadecimal integers beyond 64 bits, rounding to floating-point precision; values exceeding the float range become signed infinity, as with decimal JSON5 numbers. Dynamic Any values use json2's existing native numeric types, so re-encoding normalizes number spelling and its default f64 numbers have the usual floating-point precision limits.

strict: true controls type conversion independently of json5: it still rejects quoted numbers, non-optional null values and fixed arrays of the wrong length. encode_append and decode_reuse accept the same JSON5 options as encode and decode. JSON5 encoding releases temporary map keys. Decoded strings own their text, and decoding releases its UTF-8 scratch buffers.

Migrating from x.json5

The x.json5 module has been removed. Import json2 and add json5: true to encode, decode, parse, parse_text, parse_file and decode_file calls. Replace encode_with_opts with encode and use EncoderOptions: indent becomes prettify: true, indent_string: .... Replace @[json5: 'name'] with @[json: 'name'].

Use to_json for custom encoding and from_json_string, from_json_number, from_json_boolean or from_json_null for scalar decoding. A from_json(value Any) method decodes a whole value. Number hooks receive the original JSON5 literal, including hexadecimal spelling. String hooks follow json2's convention: escaped JSON string content without its quotes. Custom encoders return text verbatim. For JSON5, @[raw] fields contain normalized text: comments and trailing commas are removed, keys and strings use JSON quoting, and number literals retain their spelling.

parse returns json2.Any; use str() and as_array() instead of string() and array(). parse_text returns a Doc with value, value_opt, get, decode and reflect. get distinguishes missing paths (none) from explicit null values. decode_any converts a dynamic tree with the same options as decode. Doc.decode keeps the options used to parse the document. Doc.reflect leaves missing or incompatible fields at their defaults.

Use encode(text) instead of quote_string(text). To reindent a document, decode or parse it and call encode(value, prettify: true, indent_string: ' '). For iterative JSON5 scanning, use new_json5_scanner; its tokens are Json5Token with Json5TokenKind and Json5Pos source positions. String and identifier literals contain their decoded values; length preserves the original token's byte length.

Usage

encode_append[T]

encode_append(value, mut destination, options) appends JSON bytes to a caller-owned []u8, preserving its prefix and reusing capacity. Call destination.clear() before encoding to replace its contents. It accepts the same options and values as encode. The destination must have exclusive access during the call, and the value being encoded must not refer to its storage. Finish consuming the bytes before clearing or changing them. Use separate buffers for concurrent workers.

encode[T]

import json2
import time

struct Person {
mut:
    name     string
    age      ?int = 20
    birthday time.Time
    deathday ?time.Time
}

fn main() {
    mut person := Person{
        name:     'Bob'
        birthday: time.now()
    }
    person_json := json2.encode[Person](person)
    // person_json == {"name": "Bob", "age": 20, "birthday": "2022-03-11T13:54:25.000Z"}
}

Struct fields are encoded under their names or @[json: '...'] keys, including fields named after builtin types such as i64 and string. Embedded structs contribute their fields.

Enums encode as strings by default. Use @[json_as_number] on an enum to emit its integer value instead.

Integer encoding preserves the width of the input type, including int and its aliases. An int is not narrowed to i32 when written as a value, struct field, or collection element.

Floats use decimal notation for zero and magnitudes from 1e-6 (inclusive) to 1e21 (exclusive), and scientific notation outside that range, matching Go's encoding/json. Exponents omit leading zeros, for example 1e-7.

Use @[omitempty] to omit empty struct fields. For boolean fields, including optional booleans, false is empty and true is encoded. @[omitempty] only affects encoding: decode still assigns an explicit empty value such as 0 or "" from the input.

Maps encode with keys sorted lexically by their string representation, before JSON escaping. Integer keys therefore place "10" before "2". This applies to nested maps and maps held in Any, and to compact, pretty, and appended output.

decode[T]

decode_standard[T](text, options) decodes standard JSON without generating a JSON5 decoder for T. Use it for HTTP APIs, protocol messages and other standard JSON input to reduce generated code. It keeps the same lenient defaults and strict: true type conversion as decode. It always rejects JSON5 syntax, even if options.json5 is true. Existing decode[T](text) and decode[T](text, json5: true) calls keep their behavior.

import json2

struct User {
    name string
}

fn main() {
    user := json2.decode_standard[User]('{"name":"V"}')!
    println(user.name)
}

decode_reuse[T](text, mut buffer, options) accepts a DecodeBuffer and retains its token storage for the next call. It uses the same validation and decoding rules as decode. Results stay valid across reuse and errors; the buffer stores neither input strings nor decoded values. Each concurrent or reentrant call needs its own buffer. Create each independent buffer with DecodeBuffer{}. Do not copy a buffer after decoding has retained storage in it, including after an error: copies share that storage. Capacity follows the largest token count seen, so limit input sizes when appropriate. With garbage collection, assigning DecodeBuffer{} releases the retained allocation for collection when it is no longer needed.

Struct field renaming attributes are also honored when compiling with -autofree.

Floating-point values outside the target type's finite range return a decoding error. The overflow check also applies with C finite-math flags, such as -cflags '-ffast-math'. This also applies to numbers inside json2.Any, collections, and struct fields, and to quoted numeric strings accepted in default mode. Finite subnormal values remain valid; values too small to represent may round to zero.

JSON object keys are decoded to the target map key type, including signed and unsigned integer keys. Nested maps and maps stored in struct fields follow the same conversion. Enum map keys, including enum type aliases, use member names as written by encode. Member @[json: ...] attributes do not rename map keys. Unknown member names return a decoding error. Flag-enum keys, including aliases, also accept their encoded form, such as Permission{.read | .write} or Permission{} for zero, so maps with flag keys round-trip through JSON.

The target type keeps its declaring module. A program's own sum type named Any is distinct from json2.Any, including through nested dynamic arrays, fixed arrays, and maps such as json2.decode[[][2]Any](text).

Every nested value requires its enclosing array's or object's closing delimiter. Truncated containers such as [0 or {"key": 123 return an end-delimiter error, including when a complete nested value consumes the final byte of the input.

import json2
import time

struct Person {
mut:
    name     string
    age      ?int = 20
    birthday time.Time
    deathday ?time.Time
}

fn main() {
    resp := '{"name": "Bob", "age": 20, "birthday": "${time.now()}"}'
    person := json2.decode[Person](resp)!
    // struct Person {
    //    mut:
    //        name "Bob"
    //        age  20
    //        birthday "2022-03-11 13:54:25"
    //       deathday "2022-03-11 13:54:25"
    // }
}

decode[T] is smart and can auto-convert the types of struct fields - this means examples below will have the same result

Embedded struct fields are decoded from the surrounding object, including reference fields.

Decoding a pointer allocates an initialized value. Nested arrays keep their element types, and omitted struct fields retain their declared defaults, as for value fields.

json2.decode[Person]('{"name": "Bob", "age": 20, "birthday": "2022-03-11T13:54:25.000Z"}')!
json2.decode[Person]('{"name": "Bob", "age": 20, "birthday": "2022-03-11 13:54:25.000"}')!
json2.decode[Person]('{"name": "Bob", "age": "20", "birthday": 1647006865}')!
json2.decode[Person]('{"name": "Bob", "age": "20", "birthday": "1647006865"}}')!

raw decode

import json2
import net.http

fn main() {
    resp := http.get('https://reqres.in/api/products/1')!

    // This returns an Any type
    raw_product := json2.decode[json2.Any](resp.body)!
}

iterative token scanning

json2 now exposes low-level scanners that let you process JSON token by token instead of materializing the whole tree first.

Use new_scanner() for in-memory strings:

import json2

fn main() {
    mut scanner := json2.new_scanner('{"items":[1,2,3]}')
    for {
        token := scanner.next()!
        if token.is_eof() {
            break
        }
        println('${token.kind}: ${token.literal()}')
    }
}

Use new_reader_scanner() to stream tokens from a file or any io.Reader:

import os
import json2

fn main() {
    mut file := os.open('huge.json')!
    defer {
        file.close()
    }

    mut scanner := json2.new_reader_scanner(reader: file)
    defer {
        scanner.free()
    }

    for {
        token := scanner.next()!
        if token.is_eof() {
            break
        }
        if token.kind == .str && token.literal() == 'id' {
            println('found an id key')
        }
    }
}

Casting Any type / Navigating

import json2
import net.http

fn main() {
    resp := http.get('https://reqres.in/api/products/1')!

    raw_product := json2.decode[json2.Any](resp.body)!

    product := raw_product.as_map()
    data := product['data'] as map[string]json2.Any

    id := data['id'].int() // 1
    name := data['name'].str() // cerulean
    year := data['year'].int() // 2000
}

Constructing an Any type

import json2

fn main() {
    mut me := map[string]json2.Any{}
    me['name'] = 'Bob'
    me['age'] = 18

    mut arr := []json2.Any{}
    arr << 'rock'
    arr << 'papers'
    arr << json2.null
    arr << 12

    me['interests'] = arr

    mut pets := map[string]json2.Any{}
    pets['Sam'] = 'Maltese Shitzu'
    me['pets'] = pets

    // Stringify to JSON
    println(me.str())
    //{
    //   "name":"Bob",
    //   "age":18,
    //   "interests":["rock","papers","scissors",null,12],
    //   "pets":{"Sam":"Maltese"}
    //}
}

Null Values

json2 has a separate Null type for differentiating an undefined value and a null value. To verify that the field you're accessing is a Null, use [typ] is json2.Null.

fn (mut p Person) from_json(f json2.Any) {
    obj := f.as_map()
    if obj['age'] is json2.Null {
        // use a default value
        p.age = 10
    }
}

Casting a value to an incompatible type

json2 provides methods for turning Any types into usable types. The following list shows the possible outputs when casting a value to an incompatible type.

  1. Casting non-array values with as_array() will return an array with the value as the content.
  2. Casting non-map values as map (as_map()) will return a map with the value as the content.
  3. Casting non-string values to string (str()) will return the JSON string representation of the value.
  4. Casting non-numeric values to int/float (int()/i64()/f32()/f64()) will return zero.

Decoding errors

Error previews begin within the line containing the failing position. Tabs expand the displayed column count without expanding byte offsets into the input string.

Encoding using string builder instead of []u8

To be more performant, json2, in PR 20052, decided to use buffers directly instead of Writers. If you want to use Writers you can follow the steps below:

mut sb := strings.new_builder(64)
mut buffer := []u8{}

json2.encode_value(<some value to be encoded here>, mut buffer)!

sb.write(buffer)!

unsafe { buffer.free() }

Scanner and ReaderScanner join adjacent high/low UTF-16 \uXXXX escapes into one Unicode scalar value. An unpaired surrogate escape yields U+FFFD; malformed escapes still report an error. These scanner rules are separate from json2.decode.

Constants #

const null = Null{}

null is an instance of the Null type, to ease comparisons with it.

fn decode #

@[manualfree]
fn decode[T](val string, params DecoderOptions) !T

decode decodes a JSON string into a specified type. By default, decoding is lenient. Use strict: true for strict type conversion and json5: true to accept JSON5 syntax. Use decode_standard to avoid generating JSON5 decoding code for the target type. Input nested deeper than 512 array/object levels errors; the limit applies to standard JSON only, the separate JSON5 parser is not covered by it.

fn decode_any #

@[manualfree]
fn decode_any[T](value Any, params DecoderOptions) !T

decode_any converts a dynamic value into T using the existing JSON decoder.

fn decode_file #

@[manualfree]
fn decode_file[T](path string, params DecoderOptions) !T

decode_file reads and decodes a JSON or JSON5 document into T.

fn decode_reuse #

@[manualfree]
fn decode_reuse[T](val string, mut buffer DecodeBuffer, params DecoderOptions) !T

decode_reuse decodes with the same options and validation as decode, reusing buffer's token allocation and growing it during validation instead of counting values in a separate pass. Returned values remain valid when buffer is reused, including after an error. The caller must provide exclusive access to buffer. Input nested deeper than 512 array/object levels errors; the limit applies to standard JSON only, the separate JSON5 parser is not covered by it.

fn decode_standard #

@[manualfree]
fn decode_standard[T](val string, params DecoderOptions) !T

decode_standard decodes standard JSON into a specified type without generating JSON5 decoding code. It is lenient by default; use strict: true for strict type conversion. The json5 option is ignored; JSON5 syntax is always rejected. Input nested deeper than 512 array/object levels errors.

fn encode #

fn encode[T](val T, config EncoderOptions) string

encode encodes a value as JSON, or JSON5 with json5: true.

fn encode_append #

@[manualfree]
fn encode_append[T](val T, mut destination []u8, config EncoderOptions)

encode_append appends the JSON representation of val to destination, preserving its existing bytes and reusing its capacity. Clear destination before calling to replace its contents. The caller owns the buffer and must not mutate it from another thread during encoding or pass a value that aliases its storage.

fn encode_pretty #

@[deprecated: 'use `encode(..., prettify: true)` instead']
@[deprecated_after: '2025-10-30']
fn encode_pretty[T](typed_data T) string

encode_pretty ...

fn map_from #

fn map_from[T](t T) map[string]Any

map_from converts a struct to a map of Any.

fn new_doc #

fn new_doc(root Any, params DecoderOptions) Doc

new_doc wraps an already parsed Any tree.

fn new_json5_scanner #

fn new_json5_scanner(text string) &Json5Scanner

new_json5_scanner creates a Json5Scanner over text, dropping a leading byte order mark.

fn new_reader_scanner #

fn new_reader_scanner(config ReaderScannerConfig) &ReaderScanner

new_reader_scanner creates an iterative scanner that reads JSON tokens from an io.Reader.

fn new_scanner #

fn new_scanner(text string) Scanner

new_scanner creates an iterative scanner for an in-memory JSON string.

fn new_scanner_from_bytes #

fn new_scanner_from_bytes(text []u8) Scanner

new_scanner_from_bytes creates an iterative scanner for an in-memory JSON byte slice.

fn parse #

fn parse(text string, params DecoderOptions) !Any

parse parses JSON into a dynamic Any value. Set json5: true for JSON5 syntax.

fn parse_file #

@[manualfree]
fn parse_file(path string, params DecoderOptions) !Doc

parse_file reads a JSON or JSON5 document with path lookup.

fn parse_path #

fn parse_path(path string) ![]PathStep

parse_path splits a lookup path into steps. Quoted segments keep any dots they contain, so a."b.c" addresses the key b.c inside the object a.

The path is walked with an explicit index rather than a state machine, which keeps the "flush the pending key" logic in one place.

fn parse_text #

fn parse_text(text string, params DecoderOptions) !Doc

parse_text parses a JSON or JSON5 document with path lookup.

fn resolve_path #

fn resolve_path(value Any, steps []PathStep) Any

resolve_path walks steps through value, returning null when a step does not resolve.

fn Json5TokenKind.from #

fn Json5TokenKind.from[W](input W) !Json5TokenKind

from returns the Json5TokenKind value of an integer or of a field name, or an error if there is none.

fn TokenKind.from #

fn TokenKind.from[W](input W) !TokenKind

from returns the TokenKind value of an integer or of a field name, or an error if there is none.

interface BooleanDecoder #

interface BooleanDecoder {
	// called with converted bool
	// already checked so no error needed
mut:
	from_json_boolean(boolean_value bool)
}

implements decoding json true/false

interface Encodable #

@[deprecated: 'use `to_json` to implement `JsonEncoder` instead']
@[deprecated_after: '2025-10-30']
interface Encodable {
	json_str() string
}

interface JsonEncoder #

interface JsonEncoder {
	// to_json returns a string containing an objects json representation
	to_json() string
}

implements encoding json, this is not validated so implementations must be correct

interface NullDecoder #

interface NullDecoder {
	// only has one value
	// already checked so no error needed
mut:
	from_json_null()
}

implements decoding json null

interface NumberDecoder #

interface NumberDecoder {
	// called with raw string of number e.g. '-1.234e23'
mut:
	from_json_number(raw_number string) !
}

implements decoding json numbers, e.g. -1.234e23

interface StringDecoder #

interface StringDecoder {
	// called with raw string (minus apostrophes) e.g. 'hello, \u2164!'
mut:
	from_json_string(raw_string string) !
}

implements decoding json strings, e.g. "hello, \u2164!"

interface ValueDecoder #

interface ValueDecoder {
mut:
	from_json(value Any)
}

ValueDecoder lets a type decode a whole JSON or JSON5 value as a dynamic tree.

type Any #

@[markused]
type Any = []Any
	| bool
	| f64
	| f32
	| i64
	| int
	| i32
	| i16
	| i8
	| map[string]Any
	| string
	| time.Time
	| u64
	| u32
	| u16
	| u8
	| Null

fn (Any) str #

fn (f Any) str() string

str returns the string representation of the Any type. Use the json_str method. If you want to use the escaped str() version of the Any type.

fn (Any) json_str #

fn (f Any) json_str() string

json_str returns the JSON string representation of the Any type.

fn (Any) prettify_json_str #

@[deprecated: 'use `encode(Any(...), prettify: true)` instead']
@[deprecated_after: '2025-10-30']
fn (f Any) prettify_json_str() string

prettify_json_str returns the pretty-formatted JSON string representation of the Any type.

fn (Any) i8 #

fn (f Any) i8() i8

i8 uses Any as a 16-bit integer.

fn (Any) i16 #

fn (f Any) i16() i16

i16 uses Any as a 16-bit integer.

fn (Any) int #

fn (f Any) int() int

int uses Any as an integer.

fn (Any) i32 #

fn (f Any) i32() i32

i32 uses Any as a 32-bit integer.

fn (Any) i64 #

fn (f Any) i64() i64

i64 uses Any as a 64-bit integer.

fn (Any) u8 #

fn (f Any) u8() u8

u8 uses Any as a 8-bit unsigned integer.

fn (Any) u16 #

fn (f Any) u16() u16

u16 uses Any as a 16-bit unsigned integer.

fn (Any) u32 #

fn (f Any) u32() u32

u32 uses Any as a 32-bit unsigned integer.

fn (Any) u64 #

fn (f Any) u64() u64

u64 uses Any as a 64-bit unsigned integer.

fn (Any) f32 #

fn (f Any) f32() f32

f32 uses Any as a 32-bit float.

fn (Any) f64 #

fn (f Any) f64() f64

f64 uses Any as a 64-bit float.

fn (Any) bool #

fn (f Any) bool() bool

bool uses Any as a bool.

fn (Any) arr #

@[deprecated: 'use as_array() instead']
@[deprecated_after: '2026-03-27']
fn (f Any) arr() []Any

arr uses Any as an array.

fn (Any) as_array #

fn (f Any) as_array() []Any

as_array uses Any as an array.

fn (Any) as_map #

fn (f Any) as_map() map[string]Any

as_map uses Any as a map.

fn (Any) as_map_of_strings #

fn (f Any) as_map_of_strings() map[string]string

as_map_of_strings converts Any maps and arrays into maps of string values.

fn (Any) to_time #

fn (f Any) to_time() !time.Time

to_time uses Any as a time.Time.

fn ([]Any) str #

fn (f []Any) str() string

str returns the JSON string representation of the []Any type.

fn (map[string]Any) str #

fn (f map[string]Any) str() string

str returns the JSON string representation of the map[string]Any type.

enum Json5TokenKind #

enum Json5TokenKind {
	none
	error
	comment
	str
	ident
	number
	bool
	null
	infinity
	nan
	comma = 0x2C // ,
	colon = 0x3A // :
	lsbr  = 0x5B // [
	rsbr  = 0x5D // ]
	lcbr  = 0x7B // {
	rcbr  = 0x7D // }
	eof
}

Json5TokenKind identifies the kind of a JSON5 token.

enum TokenKind #

enum TokenKind {
	none
	error
	str
	float
	int
	null
	bool
	eof
	comma = 44 // ,
	colon = 58 // :
	lsbr  = 91 // [
	rsbr  = 93 // ]
	lcbr  = 123 // {
	rcbr  = 125 // }
}

TokenKind identifies the kind of a JSON token.

struct DecodeBuffer #

struct DecodeBuffer {
mut:
	values_info []ValueInfo
}

DecodeBuffer retains token storage between decode_reuse calls. Give each concurrent or reentrant decoding operation its own buffer. It never retains the input or decoded values; its capacity grows with the largest token count. Create independent buffers with DecodeBuffer{}; do not copy a buffer after decoding has retained storage in it, including after a decoding error.

struct DecoderOptions #

@[markused; params]
struct DecoderOptions {
pub:
	// json5 accepts JSON5 comments, keys, strings, trailing commas and numbers.
	json5 bool
	// In strict mode, quoted strings are not accepted as numbers.
	// For example, '"123"' will fail to decode as int in strict mode,
	// but will succeed in default mode.
	// Strict mode also requires a fixed size array to get a JSON array with exactly
	// as many elements. By default, `null` or missing trailing elements keep their
	// default values, and extra elements are ignored.
	// Strict mode also rejects `null` for a value that is not an option. By default,
	// like in the removed `json` module, `null` is the zero value of a number, bool,
	// string, enum or time, an empty array or map, and a nested struct with its
	// default field values.
	strict bool
}

DecoderOptions provides options for JSON decoding. By default, decoding is lenient. Use strict: true for strict type conversion and json5: true to accept JSON5 syntax.

struct Doc #

struct Doc {
	params DecoderOptions
pub:
	root Any
}

Doc is a parsed JSON document. Use value, value_opt or decode to read from it.

fn (Doc) to_any #

fn (d Doc) to_any() Any

to_any returns the document root as a dynamic value.

fn (Doc) str #

fn (d Doc) str() string

str returns the document rendered in the dialect it was parsed with.

fn (Doc) value #

fn (d Doc) value(key string) Any

value queries a value with a small path syntax: dots separate object keys, brackets index arrays, and a key that contains a dot can be quoted, as in a."b.c". Returns Null when the path does not resolve.

fn (Doc) value_opt #

fn (d Doc) value_opt(key string) !Any

value_opt queries a value and returns an error when the path does not resolve, instead of Null.

fn (Doc) get #

fn (d Doc) get(key string) ?Any

get queries a value and returns an option, so none distinguishes a missing key from an explicit null.

fn (Doc) decode #

fn (d Doc) decode[T]() !T

decode decodes the document into T. It is the method form of the package-level decode and shares its attribute and hook support.

fn (Doc) reflect #

fn (d Doc) reflect[T]() T

reflect sets the fields of T from the matching document keys, leaving absent fields at their default value. Fields are matched by name or by a @[json: 'name'] attribute. Unlike decode, a key that cannot be decoded into its field is silently skipped instead of reported, so a partially matching document still fills in what it can.

struct EncoderOptions #

@[params]
struct EncoderOptions {
pub:
	// json5 permits JSON5 output, including Infinity and NaN.
	json5 bool
	// These formatting options apply only when json5 is true.
	single_quotes   bool
	unquoted_keys   bool
	trailing_commas bool
	prettify        bool
	indent_string   string = '    '
	newline_string  string = '\n'

	enum_as_int bool

	escape_unicode bool
	// time_as_unix encodes a `time.Time` as its Unix timestamp in seconds, like the
	// removed `json` module did, instead of an RFC 3339 string.
	time_as_unix bool
	// legacy_layout, with `prettify: true`, lays the output out like `encode_pretty`
	// of the removed `json` module: members indented with tabs, a tab after each
	// key, and array elements on one line, separated by `, `.
	legacy_layout bool
}

EncoderOptions provides a list of options for encoding

struct Json5Pos #

struct Json5Pos {
	offset int // Byte offset in the original input, including a leading BOM.
pub:
	line int
	col  int
}

Json5Pos is a location inside the scanned text.

struct Json5Scanner #

struct Json5Scanner {
	source string
pub:
	text []rune
mut:
	pos    int
	offset int
	line   int = 1
	col    int = 1
}

Json5Scanner tokenizes JSON5 text. Whitespace and comments are treated as trivia and skipped; every other token is reported to the caller.

fn (Json5Scanner) next #

@[manualfree]
fn (mut s Json5Scanner) next() !Json5Token

next returns the next token, decoding string and identifier escapes and skipping trivia.

struct Json5Token #

struct Json5Token {
pub:
	kind   Json5TokenKind
	lit    string // Decoded value for strings and identifiers, raw source text otherwise.
	pos    Json5Pos
	length int // Token length in source bytes, before decoding escapes.
}

Json5Token is a single lexical unit produced by the Json5Scanner.

struct JsonDecodeError #

struct JsonDecodeError {
	Error
	context string
pub:
	message string

	line      int
	character int
}

struct JsonScanError #

struct JsonScanError {
	Error
pub:
	message string

	line      int
	character int
}

JsonScanError describes a tokenization error reported by the iterative scanner APIs.

struct Null #

struct Null {}

Null is a simple representation of the null value in JSON.

fn (Null) from_json_null #

@[markused]
fn (mut n Null) from_json_null()

from_json_null implements a custom decoder for json2

fn (Null) to_json #

fn (n Null) to_json() string

to_json implements a custom encoder for json2

struct PathStep #

struct PathStep {
pub:
	key   string
	index int
}

PathStep is one element of a parsed lookup path: either an object key or an array index.

fn (PathStep) is_index #

fn (s PathStep) is_index() bool

is_index reports whether the step indexes an array.

fn (PathStep) str #

fn (s PathStep) str() string

str returns the step in path syntax.

struct ReaderScanner #

struct ReaderScanner {
mut:
	reader &io.BufferedReader
	peeked bool
	ch     u8
	line   int = 1
	col    int = 1
}

ReaderScanner tokenizes JSON incrementally from any io.Reader.

fn (ReaderScanner) free #

fn (mut s ReaderScanner) free()

free releases the reader scanner's internal buffer.

fn (ReaderScanner) next #

fn (mut s ReaderScanner) next() !Token

next returns the next JSON token from the reader-backed scanner.

struct ReaderScannerConfig #

@[params]
struct ReaderScannerConfig {
pub:
	reader      io.Reader
	buffer_size int = 128 * 1024
}

ReaderScannerConfig configures a reader-backed JSON scanner.

struct Scanner #

struct Scanner {
mut:
	text []u8
	pos  int // the position of the token in scanner text
	line int = 1
	col  int = 1
}

Scanner tokenizes JSON from an in-memory string or byte slice.

fn (Scanner) next #

fn (mut s Scanner) next() !Token

next returns the next JSON token from the in-memory scanner.

struct Token #

struct Token {
pub:
	lit  []u8      // literal representation of the token
	kind TokenKind // the token number/enum; for quick comparisons
	line int       // the line in the source where the token occurred
	col  int       // the column in the source where the token occurred
}

fn (Token) literal #

fn (t Token) literal() string

literal returns the token contents as a string.

fn (Token) full_col #

fn (t Token) full_col() int

full_col returns the full column information which includes the length.

fn (Token) is_eof #

fn (t Token) is_eof() bool

is_eof reports whether the token marks the end of the JSON stream.