Skip to main content

Card

Struct Card 

Source
pub struct Card { /* private fields */ }
Expand description

A single card-yaml block (root or composable). body is the content (Content) form of the prose after the closing fence: the empty content when none follows; check card.body().is_blank(). Markdown is a projection: Card::body_markdown re-emits it.

Implementations§

Source§

impl Card

Source

pub fn new(kind: impl Into<String>) -> Result<Self, EditError>

Create a composable card with the given kind, no fields, and an empty body.

Source

pub fn store_field( &mut self, name: &str, value: impl Into<QuillValue>, ) -> Result<(), EditError>

Store a payload field verbatim, clearing any !must_fill marker on that key, the opaque store (store = verbatim, coercion deferred to render; contrast the typed TypedWriter::set). Scalars convert in place (store_field("qty", 3)); see the From impls on QuillValue.

Returns EditError::InvalidFieldName when name does not match [A-Za-z_][A-Za-z0-9_]*.

Source

pub fn store_fill( &mut self, name: &str, value: impl Into<QuillValue>, ) -> Result<(), EditError>

Store a payload field verbatim and mark it as a !must_fill placeholder. Null emits as key: !must_fill; scalars/sequences as key: !must_fill <value>. The opaque store’s fill variant (quill-free, verbatim); same validation as Card::store_field.

Source

pub fn store_fields<K, V, I>( &mut self, fields: I, ) -> Result<(), Vec<(String, EditError)>>
where K: Into<String>, V: Into<QuillValue>, I: IntoIterator<Item = (K, V)>,

Store several payload fields verbatim and atomically, clearing any !must_fill marker on each key, the opaque store’s batch (contrast the typed TypedWriter::set_all). The whole batch is validated first: on any violation nothing is applied and every offending field is reported as a (name, error) pair, so a caller feeding externally-sourced names (database columns, form keys) sees all violations in one pass instead of fix-rerun-repeat. Per-field rules are those of Card::store_field; insertion order follows the iterator, and a repeated name behaves like repeated store_field calls (last value wins, first position kept).

Source

pub fn remove_field( &mut self, name: &str, ) -> Result<Option<QuillValue>, EditError>

Remove a payload field; returns Ok(None) if the name is absent. Removal has no lane: the one verb serves every write path. Same validation as Card::store_field.

Source

pub fn store_ext(&mut self, value: Map<String, Value>) -> Result<(), EditError>

Replace the card’s opaque $ext map wholesale, inserting it at the canonical position (after $quill/$kind, before user fields) when none existed. Passing an empty map records an explicit $ext: {}.

$ext carries out-of-band consumer state (editor renames, agent annotations, …) and is stripped from Document::to_plate_json, so a write here can never affect a render. Any nested comments attached to a replaced $ext are dropped. Returns EditError::ValueTooDeep when the map nests past the §8 depth limit: $ext never reaches the plate JSON, but it does flow through the recursive emit and DTO paths, so it carries the same depth bound as user fields.

Quill-free and never coerced: an opaque store_* verb by the vocabulary rule, not a typed set.

Source

pub fn remove_ext(&mut self) -> Option<Map<String, Value>>

Remove the card’s $ext map entirely, returning the previous map if present. This is a blunt escape hatch: it discards every namespace ($ext.editor, $ext.agent, …) at once. To clear consumer state, prefer Card::remove_ext_namespace, which drops only your own slot and leaves sibling consumers’ state intact.

Source

pub fn store_ext_namespace( &mut self, namespace: impl Into<String>, value: Value, ) -> Result<(), EditError>

Merge value into the card’s $ext map under namespace, creating the map when absent and replacing any existing value at that key.

This is the recommended way to write $ext: it preserves sibling namespaces, so independent consumers keying on their own slot ($ext.editor, $ext.agent, …) don’t clobber each other. Returns EditError::ValueTooDeep when the merged map nests past the §8 depth limit (see Card::store_ext); the card’s $ext is unchanged on error. Quill-free and never coerced: an opaque store_* verb.

Source

pub fn remove_ext_namespace(&mut self, namespace: &str) -> Option<Value>

Remove namespace from the card’s $ext map, returning the value that was stored there (or None when the map or the key was absent).

This is the recommended way to clear $ext state: it is the namespace-scoped inverse of Card::store_ext_namespace and preserves sibling namespaces, where Card::remove_ext would wipe them all. When removing the last namespace empties the map, the $ext entry is dropped entirely (not left as $ext: {}), so store_ext_namespace(ns, v) followed by remove_ext_namespace(ns) restores a card that had no $ext to its original state.

Source

pub fn seed(&self) -> Option<&Map<String, Value>>

The raw $seed map (keyed by card-kind), or None. For a parsed, per-kind overlay, index this map by kind and pass the entry to crate::SeedOverlay::from_json. Only the main card carries $seed.

Source

pub fn store_seed_overlay( &mut self, card_kind: impl Into<String>, value: Value, ) -> Result<(), EditError>

Merge a card-kind’s seed overlay value into the card’s $seed map under card_kind, creating the map when absent and replacing any existing overlay for that kind. Sibling kinds are preserved: this is the per-kind-safe writer, the seed analogue of Card::store_ext_namespace. card_kind must be a valid, non-reserved composable kind (EditError::InvalidKindName / EditError::ReservedKind otherwise): $seed is keyed by composable card-kind, unlike the free-form namespaces of $ext. Returns EditError::ValueTooDeep when the merged map nests past the §8 depth limit; the card is unchanged on error. Quill-free and never coerced: an opaque store_* verb.

Source

pub fn remove_seed_overlay(&mut self, card_kind: &str) -> Option<Value>

Remove card_kind from the card’s $seed map, returning the overlay stored there (or None). When removing the last kind empties the map, the $seed entry is dropped entirely (not left as $seed: {}). The seed analogue of Card::remove_ext_namespace.

Source

pub fn overwrite_body(&mut self, content: Content)

Overwrite the body with a pre-built Content: value semantics, the native content writer, and the bottom rung of the content lane’s ladder by anchor fate: overwrite destroys, revise_body rebases, apply_body_change preserves. A content is valid by construction, so this is infallible: no markdown import, no diff, no schema check; the identity anchors of the previous body are gone (write-this-exact-value, so a to_markdown → overwrite round-trip cannot resurrect them). Use it when the caller already holds a content (a decoded canonical-JSON body, another field’s value, an editor’s serialized state). Cold-importing markdown is spelled overwrite_body(import_body(md)?) at the call site, where the anchor loss is visible.

Source

pub fn overwrite_field( &mut self, name: &str, content: Content, ) -> Result<(), EditError>

Overwrite a content field’s value with a pre-built Content: the field-level twin of overwrite_body. Value semantics: stores the canonical content JSON verbatim (identity marks and content-only marks such as underline intact), no diff, no schema check (schema-blind, like apply_field_change; commit_field is the typed door). The previous value’s anchors are gone; the incoming content’s ride along exactly. Returns EditError::InvalidFieldName for a malformed name.

Richtext codec. A plaintext field rests as its literal string, so an object landed here is off that field’s resting form: a repairable departure the next bound load (Quill::conform) converges. Write one through the typed door.

Source

pub fn revise_body( &mut self, body: impl Into<String>, ) -> Result<Delta, EditError>

Revise the body from an authored markdown string: edit semantics, the whole-document (stale-text / LLM / MCP) writer, and the receipt- returning default write path. Imports the markdown, diffs it against the current body, and rebases surviving identity anchors onto the new text (cold import + diff_import), then returns the text Delta from the old body to the new one: the change an editor bridge maps its own positions through across a whole-document replace (Delta::map_pos). Surviving identity anchors rebase; formatting marks are re-derived by the fresh import. A pathologically over-nested input (> MAX_NESTING_DEPTH) returns EditError::Import rather than silently degrading to the empty content. Discard the receipt with let _ = card.revise_body(md)?; when caret stability is not needed.

Source

pub fn revise_field( &mut self, name: &str, body: impl Into<String>, ) -> Result<Delta, EditError>

Revise a richtext field from an authored markdown string: the field-level twin of revise_body, and the field-level diff_import. The other field-content writers are the cold commit_field and the splice apply_field_change, so this is the anchor-preserving path for rewriting a richtext field’s markdown wholesale. Decodes the field’s current content as the diff base (an absent field cold-imports from empty), rebases surviving anchors onto the new text, re-stores the canonical content, and returns the text Delta.

Schema-blind by design: the content-writer stratum splices without the quill (like apply_field_change); commit_field is the typed door that enforces richtext(inline), and a violation otherwise surfaces at validate/render.

Richtext only, and the exclusion bites: this decodes the current value as markdown, which eats a plaintext field’s escapes (a \*b\* commits back as a *b*) and leaves a content object where that field’s rest is a string. The typed TypedWriter::revise_field resolves the codec from the schema and is the plaintext-safe door.

Returns EditError::InvalidFieldName for a malformed name, EditError::FieldDecode when the field is present but is not a richtext content (a scalar a store_field wrote), and EditError::Import on an over-nested markdown input.

Source

pub fn apply_body_change( &mut self, bundle: &ChangeBundle, ) -> Result<(), EditError>

Apply a committed field-change bundle to the body content: the native form-editor writer. Order is text delta → island ops → line ops → mark ops, then one terminal normalization (Content::apply_field_change); mark ranges are in final-text coordinates. Returns EditError::ContentApply when an op is out of bounds; the apply is all-or-nothing (Content::apply_field_change), so the body is unchanged on error: apply the bundle against the body the delta was computed from.

Source

pub fn apply_field_change( &mut self, name: &str, bundle: &ChangeBundle, ) -> Result<(), EditError>

Splice a content field-change bundle into a field’s stored content: the field-path twin of apply_body_change, and what lets identity marks (anchors, island ids) persist on field content across incremental edits. Decodes the field’s canonical content, applies the text delta plus any island/line/mark ops in the same all-or-nothing bundle, and re-stores the canonical result.

An absent field splices against the empty content, as revise_field diffs against it. A bundle that expected content still fails: its text delta declares the base length it was computed against, so only a zero-base bundle lands, and a zero-base bundle is one its producer computed against an empty field.

Returns EditError::InvalidFieldName for a malformed name, EditError::FieldDecode when the stored value is not a content (the caller addresses a field it knows is content-typed, exactly as when writing it), and EditError::ContentApply when the bundle applies out of bounds.

Richtext codec: schema-blind like revise_field, so a plaintext field’s stored string decodes here as markdown and a splice lands it off its resting form. The next bound load converges it.

Source§

impl Card

Source

pub fn quill(&self) -> Option<&QuillReference>

Source

pub fn kind(&self) -> Option<&str>

Source

pub fn ext(&self) -> Option<&Map<String, Value>>

Opaque $ext map for out-of-band extension data (UI editor state, agent annotations, …). Carried through Markdown and storage DTO round-trips; never emitted into the plate JSON consumed by backends.

Source

pub fn payload(&self) -> &Payload

The card’s card-yaml storage as a read view. Writes go through the enforcing verbs (store_field, TypedWriter), not through here.

Source

pub fn body(&self) -> &Content

The card body as a Content content: the canonical content model. For the markdown projection use Card::body_markdown.

Source

pub fn body_markdown(&self) -> String

The card body rendered back to its markdown projection. This is a derived view (export ∘ body), not stored state; a Document round-trip therefore canonicalizes the body (e.g. __b__**b**).

Trait Implementations§

Source§

impl Clone for Card

Source§

fn clone(&self) -> Card

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Card

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<&Card> for CardV0_93_0

Source§

fn from(card: &Card) -> Self

Converts to this type from the input type.
Source§

impl From<&Card> for CardWire

Source§

fn from(card: &Card) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for Card

Source§

fn eq(&self, other: &Card) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Card

Source§

impl TryFrom<CardV0_93_0> for Card

Source§

type Error = StorageError

The type returned in the event of a conversion error.
Source§

fn try_from(card: CardV0_93_0) -> Result<Self, Self::Error>

Performs the conversion.
Source§

impl TryFrom<CardWire> for Card

Source§

type Error = WireError

The type returned in the event of a conversion error.
Source§

fn try_from(wire: CardWire) -> Result<Self, Self::Error>

Performs the conversion.

Auto Trait Implementations§

§

impl Freeze for Card

§

impl RefUnwindSafe for Card

§

impl Send for Card

§

impl Sync for Card

§

impl Unpin for Card

§

impl UnsafeUnpin for Card

§

impl UnwindSafe for Card

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.