alux-shape-json 0.1.0

JSON interpretation of ALUX data shapes
Documentation

alux-shape-json

alux-shape-json interprets an alux-shape term as a decision about a JSON value.

use alux_shape::{FieldAlg, ShapeAlg, ShapeExt, Spelling};
use alux_shape_json::Judge;
use serde_json::json;

let alg = Judge::new(Spelling::LowerCamel);
let checksum = alg.field(&["checksum"], alg.bytes_hex(Some(2)));
let display_name = alg.field(&["display", "name"], alg.text());

let user = alg.named_product(&["user"], vec![checksum, display_name]);

assert!(user.holds(&json!({"checksum": "0xbeef", "displayName": "ada"})).is_ok());

// The surface says how a name is written, so a differently spelled key is a different value.
assert!(user.holds(&json!({"checksum": "0xbeef", "display_name": "ada"})).is_err());

This is the interpretation that makes a shape answerable rather than merely describable: a term either describes what was written or names where it did not. Judging is strict in both directions — a member the shape describes must be present unless it may be absent, and a member the value carries must be described — because a shape that quietly tolerates an extra key cannot be trusted to state what a type writes.

A name is spelled here as the surface spells it, which is why Judge::new takes a Spelling and the term does not carry one.

Two things it does not decide on its own. Bare bytes describe no JSON value, since nothing states how they are written; bytes_hex or base64 does. And a reference describes anything, because resolving a name needs the whole shape at once rather than the fold that builds it — so a term read back by alux-shape-term is resolved first, and then a name states what it introduced.