Any Type for JSON and YAML
Build and access JSON/YAML data using a dynamic sumtype instead of static types.
- Type
Any
accomodating all JSON types - null
, boolean
, number
, string
, array
and object
. - Strict extraction of values checking for the right return type.
- Safe conversion of all numberic types (
u8
, u16
, u32
, u64
, i8
, i16
, int
, i64
and f32
) checking for arithmetic overflow. - Factory functions for creating JSON values.
- Built-in formatting to
string
for easy logging. - Convenient traversing of nested values in arrays and objects.
- Unmarshalling
Any
data to a static V type and marshalling a V value to Any
data.
Used in
prantlf.json
Attention
prantlf.jsany
prantlf.jany
Synopsis
import prantlf.jany { Any, Null, any_int, marshal, MarshalOpts, unmarshal, UnmarshalOpts }
// Create an Any
any := any_int(42) // factory function
any := Any(f64(42)) // cast to sumtype
// Checks for null
if any is Null {}
if any.is_null() {}
// Get a value
val := any.number()! // get a number (f64)
val := any.int()! // get an integer
// Format a value to string
str := any.str()
// Get a value on a path
val := any.get('a.b[0]')!
// Set a value on a path
any.set('a.b[0]', any_int(42))!
// Marshal a statically typed value to an Any
struct Config {
answer int
}
config := Config{ answer: 42 }
any := marshal(config, MarshalOpts{})
// Unmarshal an Any to a static type
struct Config {
answer int
}
any := Any({
'answer': Any(f64(42))
})
config := unmarshal[Config](any, UnmarshalOpts{})
Installation
You can install this package either from
VPM
v install prantlf.jany
v install --git https://github.com/prantlf/v-jany
API
The type
Any
// JSON types: null boolean number string array object
pub type Any = Null | bool | f64 | string | []Any | map[string]Any
Null
The
null
jany
pub const null = Null{}
Null
null
is
is_null()
if any is Null {}
if any.is_null() {}
Types
Built-in V types are mapped to JSON types in the following way:
JSON type | V type |
---|---|
null |
Null |
boolean |
bool |
number |
f64 |
string |
string |
array |
[]Any |
object |
map[string]Any |
The native V type of an
Any
is
if any is string {}
The name of the JSON type of an
Any
.typ()
typ := any.typ()
Factories
An
Any
jany
JSON type | V type | Casting | Factory |
---|---|---|---|
null |
Null |
Any(null) |
.any_null() |
boolean |
bool |
Any(true) |
.any_boolean(true) |
number |
f64 |
Any(f64(1)) |
.any_number(1) |
string |
string |
Any('a') |
.any_string('a') |
array |
[]Any |
Any([Any(f64(1))]) |
.any_array([1]) |
object |
map[string]Any |
Any({'a': Any(f64(1))}) |
.any_object({ 'a': 1 }) |
Getters
For V types mapped from JSON types, there're getters. If the JSON value doesn't match the type of the getter, an error will be returned:
JSON type | V type | Getter |
---|---|---|
null |
Null |
.is_null() |
number |
f64 |
.number() |
boolean |
bool |
.boolean() |
string |
string |
.string() |
array |
[]Any |
.array() |
object |
map[string]Any |
.object() |
Except for the basic V types mapped from JSON types, there're additional getters for other numeric V types. If the JSON value doesn't match the type of the getter, or of the numeric type cannot accomodate the value and an arithmetic overflow would occur, an error will be returned:
JSON type | V type | Getter |
---|---|---|
number |
u8 |
.u8() |
number |
u16 |
.u16() |
number |
u32 |
.u32() |
number |
u64 |
.u64() |
number |
i8 |
.i8() |
number |
i16 |
.i16() |
number |
int |
.int() |
number |
i64 |
.i64() |
number |
f32 |
.f32() |
Formatting
Serialisation of an
Any
Any
.str()
str := any.str()
Traversing
Values nested in arrays objects can be obtained by a convenience function using a string path -
.get(...)
[usize]
.
"
'
[
]
.
val := any.get('a.b[0]')!
Similarly to getting a nested value, a nested value can be set too. If the parent value on the path (the one but last value) is missing, an error will be returned. Arrays need to have the proper length before assigning values to them:
any.set('a.b', Any([]Any{}))!
any.set('a.b[0]', any_int(42))!
A new item can be added to an array too:
any.add('a.b', any_int(42))!
Marshalling
Except for using
Any
jany
marshal[T](value T, opts &MarshalOpts) !Any
Marshals a value of
T
Any
MarshalOpts
Name | Type | Default | Description |
---|---|---|---|
enums_as_names |
bool |
false |
stores
string
int
|
struct Config {
answer int
}
config := Config{ answer: 42 }
any := marshal(config, MarshalOpts{})!
unmarshal[T](any Any, opts &UnmarshalOpts) !T
Unmarshals an
Any
T
UnmarshalOpts
Name | Type | Default | Description |
---|---|---|---|
require_all_fields |
bool |
false |
requires a key in the source object for each field in the target struct |
forbid_extra_keys |
bool |
false |
forbids keys in the source object not mapping to a field in the target struct |
cast_null_to_default |
bool |
false |
allows
null
null
|
ignore_number_overflow |
bool |
false |
allows losing precision when unmarshaling numbers to smaller numeric types |
struct Config {
answer int
}
any := Any({
'answer': Any(f64(42))
})
config := unmarshal[Config](any, UnmarshalOpts{})!
unmarshal_to[T](any Any, mut typ T, opts &UnmarshalOpts) !
Unmarshals an
Any
T
UnmarshalOpts
Name | Type | Default | Description |
---|---|---|---|
require_all_fields |
bool |
false |
requires a key in the source object for each field in the target struct |
forbid_extra_keys |
bool |
false |
forbids keys in the source object not mapping to a field in the target struct |
cast_null_to_default |
bool |
false |
allows
null
null
|
ignore_number_overflow |
bool |
false |
allows losing precision when unmarshaling numbers to smaller numeric types |
struct Config {
answer int
}
any := Any({
'answer': Any(f64(42))
})
mut config := Config{}
config := unmarshal_to(any, mut config, UnmarshalOpts{})!
Contributing
In lieu of a formal styleguide, take care to maintain the existing coding style. Lint and test your code.
License
Copyright (c) 2023-2024 Ferdinand Prantl
Licensed under the MIT license.