Expand description
Schema-bound typed reader: the read twin of
TypedWriter.
The read surface’s verbs split by read-vs-write, but the deeper fault line is
interpret-vs-transport. The verbatim payload().get
(the WASM binding’s Document.getStored) is transport: it returns the stored
value verbatim, schema-free and round-trippable, the disambiguation / debug
read. Projecting a field to
markdown is interpretation: a schema-shaped question (“this field’s
richtext, as markdown”) that a schema-free Document cannot answer without
guessing which fields are even richtext. Card::field_markdown carries the
projection but has no schema to name the field set, so an unknown field name
reads back as absent rather than as the typo it is.
Quill::reader binds the schema (where the authority
already lives, the writer’s twin) so a single verb interprets by the field’s
declared type:
let v = quill.reader(&doc);
v.get("subject")?; // richtext → Some(Markdown(..))
v.get("qty")?; // integer → Some(Value(3))
v.get("absent")?; // absent → None
v.get("nope"); // unknown name → Err(UnknownField)
v.card(2)?.get("body")?; // card field, kind resolves its schemaabsence returns; mismatch raises; an unknown name is a typo. A richtext
field projects to markdown (ReadValue::Markdown) and a plaintext field
to its literal text (ReadValue::Plaintext); every other declared type
returns its canonical value verbatim (ReadValue::Value): the same
transport Document reads, now reached with schema authority. A present value
that does not decode under a content field raises
EditError::FieldRichtextDecode, the mismatch Card::field_markdown /
Card::field_plaintext surfaces. A name the schema does not declare raises
EditError::UnknownField, exactly as TypedWriter::set
rejects it on the write side.
get_content is the same read at the other end of
the codec: the corpus rather than the projection. A document that came
through the bound door (Quill::parse /
Quill::conform) rests at one form per codec, but
one the transport door left rests as authored, so the verbatim payload read
still answers “corpus or string?” with “depends where this document came
from” and this one does not. Decoding needs the
schema, not the payload: a richtext string is markdown and a plaintext
string is literal text, so the same bytes decode two ways and only the
declared type says which. That is why the corpus read binds the quill and
Document carries none.
The body read stays quill-free: a body’s type is a format fact, not a schema
fact, so get_body mirrors
Card::body_markdown rather than consulting the
schema.
Like TypedWriter, a bound reader holds &Document
and &QuillConfig, so
it cannot cross a binding boundary that carries no lifetimes (wasm-bindgen /
pyo3); those surfaces construct one per call from the quill handle.
Structs§
- Card
Reader - A single composable card bound to its
CardSchema, fromTypedReader::card. Sameget/get_bodyverbs asTypedReader, reading the card at its bound index. - Typed
Reader - A
Documentbound to itsQuillConfigfor typed reads. Construct withQuill::reader. Reads target the main card; usecardfor a composable card. The read twin ofTypedWriter.
Enums§
- Read
Value - The interpreted value at a field address: the output of
TypedReader::get. A content field decodes to its codec’s projection (richtextto markdown,plaintextto literal text); every other declared type carries its canonical value verbatim (the transport read, reached through the schema). Absence is theNoneof the enclosingOption, not a variant here.