Schemas

Collections

Arrays, tuples, sets, maps and records.
ConstructorJSON inputOutput
vld::array(s)arrayVec<T>
(a, b, …)array of fixed length (1 to 12 items)(A, B, …)
vld::set(s)arrayHashSet<T>
vld::map(k, v)array of [key, value] pairsHashMap<K, V>
vld::record(v)objectHashMap<String, V>
vld::record_with_keys(k, v)objectHashMap<K, V>
.ordered() on recordsobjectBTreeMap<…>

Element issues carry the index or key in their path ([2], .tags[0]).

Array

use vld::prelude::*;

let tags = vld::array(vld::string().min(1)).min_len(1).max_len(10).unique();
assert!(tags.parse(r#"["rust", "zod"]"#).is_ok());

let err = tags.parse(r#"["a", "a", ""]"#).unwrap_err();
// not_unique at [1], too_small at [2]
MethodCheck
min_len(n) / max_len(n) / len(n)number of items
non_empty()min_len(1)
unique()no repeated items; numbers compare by value (1 equals 1.0); each repeat is reported at its own index
contains(value)the array holds this JSON value
min_contains(n) / max_contains(n)how many times the contains value appears (no effect without contains)

Tuple

A Rust tuple of schemas is itself a schema. Tuples from 1 to 12 elements are supported. The input must have exactly that many items.

let point = (vld::number(), vld::number());
assert_eq!(point.parse("[1.5, 2]").unwrap(), (1.5, 2.0));
assert!(point.parse("[1]").is_err()); // invalid_length (origin tuple)

JSON Schema uses prefixItems.

Set

vld::set(s) reads an array into a HashSet. Duplicates are merged silently (the JSON Schema has no uniqueItems). min_size(n) / max_size(n) count unique items.

let roles = vld::set(vld::enumeration(&["admin", "user"])).min_size(1);
assert_eq!(roles.parse(r#"["user", "user"]"#).unwrap().len(), 1);

Map

vld::map(k, v) reads an array of [key, value] pairs, so keys can be any schema, not only strings. A repeated key fails with duplicate_key; an entry that is not a pair fails with invalid_map_entry.

let scores = vld::map(vld::u32(), vld::string());
let m = scores.parse(r#"[[1, "one"], [2, "two"]]"#).unwrap();
assert_eq!(m[&2], "two");

Record

vld::record(v) reads a JSON object and validates every value. min_keys(n) / max_keys(n) bound the number of keys.

let prices = vld::record(vld::number().positive()).max_keys(100);
let map = prices.parse(r#"{"apple": 1.2, "pear": 0.8}"#).unwrap();
assert_eq!(map.len(), 2);

vld::record_with_keys(key_schema, value_schema) also validates and converts keys. Each key is passed to the key schema as a JSON string, so use string schemas, enumeration(), enum_of() or from_str() (for numeric keys):

use std::collections::HashMap;

let scores = vld::record_with_keys(vld::from_str::<u32>(), vld::number());
let map: HashMap<u32, f64> = scores.parse(r#"{"1": 9.5, "2": 7}"#).unwrap();
assert_eq!(map[&1], 9.5);

let by_role = vld::record_with_keys(vld::enumeration(&["admin", "user"]), vld::boolean()).ordered();
let m = by_role.parse(r#"{"user": true, "admin": false}"#).unwrap();
assert_eq!(m.keys().collect::<Vec<_>>(), ["admin", "user"]);

.ordered() returns a BTreeMap with sorted keys (type alias ZOrderedRecord). If two keys parse to the same output key, the later one wins.