Skip to main content

Module reader

Module reader 

Source
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. So the projection has one door, and it binds the schema.

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 schema

absence 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::FieldDecode. 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 Content 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 “content object 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 Content 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 body_markdown 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§

CardReader
A single composable card bound to its CardSchema, from TypedReader::card. Same get / body_markdown verbs as TypedReader, reading the card at its bound index.
TypedReader
A Document bound to its QuillConfig for typed reads. Construct with Quill::reader. Reads target the main card; use card for a composable card. The read twin of TypedWriter.

Enums§

ReadValue
The interpreted value at a field address: the output of TypedReader::get. A content field decodes to its codec’s projection (richtext to markdown, plaintext to literal text); every other declared type carries its canonical value verbatim (the transport read, reached through the schema). Absence is the None of the enclosing Option, not a variant here.