Expand description
§alux-shape
alux-shape describes the shape of data independently of any encoder.
The crate is a specification. It carries no interpreter and depends only on
alux-ext: a shape is described here as first-order syntax over two
sorts, and an interpretation gives that description reality — a declaration in another language, a
judgement about a value, a writer of bytes, a memory layout. None of those is the type of the thing
described; each is what the term means to that interpreter.
use alux_shape::{FieldAlg, ShapeAlg, ShapeExt, Words};
const USER: Words<'static> = &["user"];
/// A shape is a term, polymorphic in the algebra that interprets it.
fn user<A>(alg: &A) -> A::Ty
where
A: ShapeAlg + FieldAlg,
{
let id = alg.field(&["id"], alg.int(false, 64));
let display_name = alg.field(&["display", "name"], alg.text());
let checksum = alg.field(&["checksum"], alg.bytes_hex(Some(32)));
alg.named_product(USER, vec![id, display_name, checksum])
}§A name is a sequence of words
[display, name] is a name. displayName, display_name, and DisplayName are three spellings
of it, and which one appears is settled where the term is interpreted. Holding words rather than a cased string is
what makes that exact: converting between cases is heuristic wherever acronyms or digits meet a
boundary, while joining words is not, so the same term spells identically in every host because none
of them re-segments anything.
ShapeAlg::named states an identity, not an instruction. An interpretation that declares types emits
one and refers to it; one that types structurally may spell the shape at each use.
§Two ways in
A type that already exists states its term through #[derive(Shape)], re-exported here and
implemented by alux-shape-macros: it reads the serde attributes already
present, so the shape and the serialization are two readings of one annotation. A shape with no
layout behind it is declared over the algebra instead.
Either way the term is the same, which is what lets a type move between them: fold both readings through an interpretation and compare.
§What it owns, and what it does not
It owns eighteen primitives and the operations they derive. Every tagged encoding of a choice is a
choice of products over a name-valued discriminant, so sum_external, sum_internal,
sum_adjacent, sum_untagged, and sum_of_names are stated once in an extension rather than being
primitives an interpretation could disagree about.
It owns no spelling, no encoder, and no layout. Whether a member is read by its name or by its position is not stated in a term either, and cannot be: a member is a lens, and which coordinate addresses it is settled when a shape is composed with a transport.
§Seeing one in a language
A term says nothing about how a host writes it, so what a shape looks like in a language is an interpretation of the term rather than a property of it. Two exist for languages people read:
alux-shape-rustreads a term as a Rust layout,structdeclarations with theserdeattributes that make the encoding agree with the shape, and a written form for each leaf soHex<[u8; 32]>stays distinct from the bytes it writes.alux-shape-typescriptreads the same term as TypeScript declarations, where a product is an interface, a merge is an intersection, and an optional member is a union withnull.
The same value folds through both, so a type stated once is available in either language without being
written in either. Four more interpretations exist for other purposes:
alux-shape-text for a readable description,
alux-shape-json for a decision about a JSON value,
alux-shape-term for the term itself, and
alux-shape-morph for a shape stated in terms of another.
And you can write your own. An interpretation is two carrier types and the primitives over them,
Sorts, ShapeAlg, and FieldAlg. Everything derived comes with them: the five encodings of a choice
are stated once in an extension, so an interpretation that never mentions them still has them.
Nothing in this crate learns about a new language, which is the point of the term being first-order.
Structs§
- Record
- A product being stated, holding the algebra it is stated against.
Enums§
- Spelling
- The spellings a name can be written in.
Traits§
- Field
Alg - The member sort: the ways one member of a product arises.
- Shape
Alg - The shape sort: what data is, and how it is written.
- Shape
Declare Ext - The operations a declaration’s body states.
- Shape
Ext - The shape operations that follow from the primitives alone.
- ShapeOf
- States a type’s shape in whichever vocabulary an interpretation provides.
- Shape
Program Alg - States the shape a declaration denotes, once an algebra interprets it.
- Shape
Program Ext - Compiles a shape declaration with an interpretation.
- Shape
Tagged Ext - The encodings of a choice that state a discriminant, which is what needs a member to state it in.
- Sorts
- The sorts of a data shape.
Functions§
- words_
of - Names the words an identifier states, splitting where it marks a boundary.
Type Aliases§
- Words
- A name: the words it is made of, in order.
Attribute Macros§
- shape_
layout - Emits the layouts a block of shape declarations states, beside the declarations themselves.
Derive Macros§
- Shape
- States
ShapeOffor a layout, reading its members and their names from the type.