x.json2 #
The name
json2was chosen to avoid any unwanted potential conflicts with the
existing codegen tailored for the mainjsonmodule which is powered by CJSON.
x.json2 is an experimental JSON parser written from scratch on V.
Usage
encode[T]
import x.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"}
}
decode[T]
import x.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.
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 x.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
x.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 x.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 x.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 x.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 x.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
x.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
x.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.
- Casting non-array values with
as_array()will return an array with the value as the content. - Casting non-map values as map (
as_map()) will return a map with the value as the content. - Casting non-string values to string (
str()) will return theJSON string representation of the value.4. Casting non-numeric values to int/float (int()/i64()/f32()/f64()) will return zero.
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() }
Constants #
const null = Null{}
null is an instance of the Null type, to ease comparisons with it.
fn decode #
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 JSON spec compliance.
fn encode #
fn encode[T](val T, config EncoderOptions) string
encode is a generic function that encodes a type into a JSON string.
fn encode_pretty #
fn encode_pretty[T](typed_data T) string
fn map_from #
fn map_from[T](t T) map[string]Any
map_from converts a struct to a map of Any.
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 raw_decode #
fn raw_decode(src string) !Any
fn TokenKind.from #
fn TokenKind.from[W](input W) !TokenKind
fn ValueKind.from #
fn ValueKind.from[W](input W) !ValueKind
interface BooleanDecoder #
interface BooleanDecoder {
mut:
// called with converted bool
// already checked so no error needed
from_json_boolean(boolean_value bool)
}
implements decoding json true/false
interface Encodable #
interface Encodable {
json_str() string
}
Encodable is an interface, that allows custom implementations for encoding structs to their string based JSON representations.
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 {
mut:
// only has one value
// already checked so no error needed
from_json_null()
}
implements decoding json null
interface NumberDecoder #
interface NumberDecoder {
mut:
// called with raw string of number e.g. '-1.234e23'
from_json_number(raw_number string) !
}
implements decoding json numbers, e.g. -1.234e23
interface StringDecoder #
interface StringDecoder {
mut:
// called with raw string (minus apostrophes) e.g. 'hello, \u2164!'
from_json_string(raw_string string) !
}
implements decoding json strings, e.g. "hello, \u2164!"
fn (Any) arr #
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
fn (Any) bool #
fn (f Any) bool() bool
bool uses Any as a bool.
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) i16 #
fn (f Any) i16() i16
i16 uses Any as a 16-bit 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) i8 #
fn (f Any) i8() i8
i8 uses Any as a 16-bit integer.
fn (Any) int #
fn (f Any) int() int
int uses Any as an integer.
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 #
fn (f Any) prettify_json_str() string
prettify_json_str returns the pretty-formatted JSON string representation of the Any type.
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) to_time #
fn (f Any) to_time() !time.Time
to_time uses Any as a time.Time.
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) u8 #
fn (f Any) u8() u8
u8 uses Any as a 8-bit unsigned integer.
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 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 DecoderOptions #
struct DecoderOptions {
pub:
// 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 bool
}
DecoderOptions provides options for JSON decoding. By default, decoding is lenient. Use strict: true for strict JSON spec compliance.
struct EncoderOptions #
struct EncoderOptions {
pub:
prettify bool
indent_string string = ' '
newline_string string = '\n'
enum_as_int bool
escape_unicode bool
}
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 #
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 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 #
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.
- README
- Constants
- fn decode
- fn encode
- fn encode_pretty
- fn map_from
- fn new_reader_scanner
- fn new_scanner
- fn new_scanner_from_bytes
- fn raw_decode
- fn TokenKind.from
- fn ValueKind.from
- interface BooleanDecoder
- interface Encodable
- interface JsonEncoder
- interface NullDecoder
- interface NumberDecoder
- interface StringDecoder
- type Any
- type []Any
- type map[string]Any
- enum TokenKind
- struct DecoderOptions
- struct EncoderOptions
- struct JsonDecodeError
- struct JsonScanError
- struct Null
- struct ReaderScanner
- struct ReaderScannerConfig
- struct Scanner
- struct Token