Collections
| Constructor | JSON input | Output |
|---|---|---|
vld::array(s) | array | Vec<T> |
(a, b, …) | array of fixed length (1 to 12 items) | (A, B, …) |
vld::set(s) | array | HashSet<T> |
vld::map(k, v) | array of [key, value] pairs | HashMap<K, V> |
vld::record(v) | object | HashMap<String, V> |
vld::record_with_keys(k, v) | object | HashMap<K, V> |
.ordered() on records | object | BTreeMap<…> |
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]
| Method | Check |
|---|---|
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.