Skip to main content

Sheet

Struct Sheet 

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

Owns a complete property model constraint graph.

Create cells with Sheet::add_cell, define multi-way constraints with Sheet::add_relationship, write input values with Sheet::write, then call Sheet::propagate to update derived cells. Propagation automatically reuses eligible prepared plans or plans again when necessary.

After a mutating operation returns an error, the sheet’s state is unspecified. Do not inspect or reuse it; discard it and rebuild from host-owned inputs.

§Example

use adam_rs::{Sheet, Method};

let mut sheet = Sheet::new();
let a = sheet.add_cell(0_i32);
let b = sheet.add_cell(0_i32);
sheet.add_relationship(vec![Method::from_fn_1_1(a, b, |x: &i32| Ok(*x * 2))]).unwrap();
sheet.write(a, 3_i32).unwrap();
assert_eq!(*sheet.read::<i32>(a).unwrap(), 3);

Implementations§

Source§

impl Sheet

Source

pub fn new() -> Self

Creates an empty sheet with no cells or relationships.

§Examples

See Sheet’s example.

Source

pub fn add_cell<T: Any + PartialEq + 'static>(&mut self, value: T) -> CellId

Registers a cell with an initial value and returns a stable handle.

The cell’s TypeId is fixed at creation time; subsequent write and read calls that use a different type will return Error::TypeMismatch.

Each call increments the sheet’s internal strength counter and sets bit 63 of the result. This partitions the strength space: written/added cells always have higher strength than derived cells, ensuring stability across conditional branch switches.

  • Complexity: Amortized O(1), plus O(A) when invalidation releases the final owners of prepared artifacts of total size A.
§Examples

See the graph example.

Source

pub fn add_source<T: Any + PartialEq + 'static>(&mut self, value: T) -> CellId

Registers a cell that can never be claimed as any method’s output — always a planner source, forever.

  • Complexity: Amortized O(1), plus O(A) when invalidation releases the final owners of prepared artifacts of total size A.
§Examples

See the graph example.

Source

pub fn cell_type_id(&self, id: CellId) -> Option<TypeId>

Returns the fixed concrete type of a live cell, or None for an invalid ID.

§Examples
use std::any::TypeId;
use adam_rs::{CellId, Sheet};
let mut sheet = Sheet::new();
let cell = sheet.add_cell(7i32);
assert_eq!(sheet.cell_type_id(cell), Some(TypeId::of::<i32>()));
assert_eq!(sheet.cell_type_id(CellId::default()), None);
Source

pub fn cell_kind(&self, id: CellId) -> Option<CellKind>

Returns id’s fixed cell kind.

Returns None if id is not a live cell in this sheet.

§Examples

See the graph example.

Source

pub fn add_relationship( &mut self, methods: Vec<Method>, ) -> Result<RelationshipId, Error>

Registers a relationship defined by a non-empty list of methods.

All methods are validated: their declared TypeIds must match the registered cells, and each method must have at least one output. A method with no inputs is explicitly allowed: it defines a fixed point (a constant, independent of every other cell) rather than a derivation. On success the RelationshipId is added to each adjacent cell’s adjacency list.

A cell that appears in both a method’s inputs and its outputs is a self-referencing cell and is explicitly allowed.

§Errors
  • Error::InvalidMethod — methods is empty, or a method has no outputs.
  • Error::MismatchedMethodCells — some method’s inputs ∪ outputs differs from another method’s in the same relationship.
  • Error::InvalidMethodOutputs — a method’s own outputs list names a cell more than once, or two methods in the same relationship have identical or nested outputs sets. Overlapping non-nested output sets are allowed.
  • Error::InvalidId — a CellId in any method is not found in this sheet.
  • Error::TypeMismatch — a method’s declared TypeId does not match the cell’s registered TypeId.
  • Error::InvalidCellKind — a method’s output cell is Source- or Out-kind.

Guard independence is checked by Sheet::validate and by Sheet::propagate, not by this mutator.

  • Complexity: O(m² × c) where m is the total number of methods and c is the maximum number of cells per method, due to pairwise output-set comparison, plus O(A) when invalidation releases the final owners of prepared artifacts of total size A.
§Examples

See the graph example.

Source

pub fn add_conditional<T: Any + PartialEq + 'static>( &mut self, source: MatchExpr, branches: Vec<(Vec<T>, Vec<RelationshipId>)>, default: Vec<RelationshipId>, ) -> Result<ConditionalId, Error>

Registers a conditional that activates relationships based on the value of a match subject: either a single existing cell, or a MatchExpr computed from multiple input cells.

Each element of branches is (keys, relationships): when the match subject’s value equals any key in keys, the branch’s relationships are added to the active set for propagate. Branches are evaluated in definition order; first match wins. default holds relationships activated when no branch matches; pass an empty Vec for no default.

§Errors
  • Error::InvalidId — the match subject references a cell not in this sheet.
  • Error::TypeMismatch — (expression match subject only) an input cell’s registered type doesn’t match the expression’s declared type for that input.
  • Error::InvalidConditional — the match subject’s output type does not match T; a referenced relationship does not exist; a relationship already appears in another conditional branch; or a branch has no keys.
  • Error::InvalidCellKind — a referenced relationship is a fixed Out writer.

Guard independence is checked by Sheet::validate and by Sheet::propagate, not by this mutator.

  • Complexity: O(I + K + E) time and O(K + R) space for match inputs I, branch keys K, referenced relationships R and their total method-output edges E, plus O(A) when invalidation releases final prepared artifacts of size A.
§Examples

See the graph example.

Source

pub fn add_requirement( &mut self, cell: CellId, requirement: Requirement, ) -> Result<RequirementId, Error>

Attaches a requirement to cell and returns its stable ID.

requirement.inputs may be any cells in the sheet, not only cell itself. The predicate runs during propagation, so callers can report false results separately from propagation failures.

§Errors
  • Error::InvalidId — cell, or one of requirement’s input cells, is not a live cell in this sheet.

  • Error::TypeMismatch — an input’s declared type does not match its cell’s registered type.

  • Error::InvalidRequirement — the input signature is invalid.

  • Complexity: O(k) where k is requirement’s input count, plus O(A) when invalidation releases the final owners of prepared artifacts of total size A.

§Examples
use adam_rs::{Requirement, Sheet};
let mut sheet = Sheet::new();
let cell = sheet.add_cell(1_i32);
let id = sheet.add_requirement(cell, Requirement::from_fn_1(cell, |x: &i32| Ok(*x > 0)))?;
assert_eq!(sheet.cell_requirements(cell), Some([id].as_slice()));
Source

pub fn add_out( &mut self, writer: Method, requirements: Vec<Requirement>, ) -> Result<CellId, Error>

Registers writer as the sole producer of its one output cell, which becomes an out cell: always derived by writer, never write()-able, but otherwise an ordinary, freely-referenceable cell. requirements are attached to that cell one at a time, in order, via Sheet::add_requirement.

§Errors
  • Error::InvalidOutput — writer does not have exactly one output cell.

  • Error::InvalidCellKind — the writer’s output cell is already Source or Out kind, or already claimed as some existing method’s output.

  • Any error Sheet::add_relationship or Sheet::add_requirement can return.

  • Postcondition: not atomic — if add_requirement fails partway through requirements, the output cell is left Out-kind, writer is already registered as its producer, and every requirement before the failing one is already attached; none of this is rolled back on error.

  • Complexity: O(k + i + m²×c) where k is the number of requirements and i is their total input count, plus the cost of add_relationship for writer alone (m = 1 method, c = cells in that method), plus O(A) when invalidation releases the final owners of prepared artifacts of total size A.

§Examples
use adam_rs::{Method, Requirement, Sheet};
let mut sheet = Sheet::new();
let input = sheet.add_cell(1_i32);
let output = sheet.add_cell(0_i32);
let id = sheet.add_out(
    Method::from_fn_1_1(input, output, |x: &i32| Ok(*x)),
    vec![Requirement::from_fn_1(output, |x: &i32| Ok(*x > 0))],
)?;
assert_eq!(id, output);
sheet.propagate()?;
assert!(sheet.cell_requirements_valid(output));
Source

pub fn add_filter(&mut self, cell: CellId, filter: Filter) -> Result<(), Error>

Attaches filter to cell.

Never evaluates filter’s function — attaching a filter is not a fresh external input, so it never changes cell’s current effective value. The next full Sheet::propagate call conforms cell via the planner’s PlanStep::FilterReclamp step; until then, read() reflects whatever cell held before this call.

§Errors
  • Error::InvalidId — cell, or one of filter’s argument cells, is not a live cell in this sheet.
  • Error::InvalidFilter — cell already has a filter, filter’s own value type does not match cell’s registered type, or filter’s argument list names cell itself.
  • Error::TypeMismatch — an argument cell’s registered type does not match the type filter declared for it.

Guard independence is checked by Sheet::validate and by Sheet::propagate, not by this mutator.

  • Complexity: O(a) where a is the number of filter argument cells, plus O(A) when invalidation releases the final owners of prepared artifacts of total size A.
§Examples

See the graph example.

Source

pub fn filter_args(&self, id: CellId) -> Option<&[CellId]>

Returns the argument cells of id’s filter, in declaration order.

Returns None if id is not a live cell in this sheet, or has no filter.

§Examples

See the graph example.

Source

pub fn filter_dependents(&self, id: CellId) -> &[CellId]

Returns the live cells whose filter references id as one of its dynamic arguments — the reverse of a filter’s own argument list (Sheet::filter_args).

  • Postcondition: empty if no live cell’s filter references id.
§Examples

See the graph example.

Source

pub fn filter_kind(&self, id: CellId) -> Option<&FilterKind>

Returns the kind of validation/derivation id’s filter performs, if it has one.

Returns None if id is not a live cell in this sheet, or has no filter.

§Examples

See the graph example.

Source

pub fn filter_range<T: Any>(&self, id: CellId) -> Option<(T, T)>

Returns id’s filter’s current (lo, hi) bounds, if it has a FilterKind::Range filter.

Resolves the filter’s argument cells’ current effective values via the same path Sheet::add_filter already uses, then calls the filter’s bounds function.

Returns None if id is not a live cell in this sheet, has no filter, its filter’s kind isn’t FilterKind::Range, its bounds have a different type from T, or the range expression fails to evaluate against the filter’s current argument values (e.g. a fallible arithmetic op in a range endpoint) — the same degraded-to-None outcome as any other reason no live bounds are available right now.

  • Complexity: O(a) where a is the number of the filter’s argument cells.
§Examples

See the graph example.

Source

pub fn filter_violation(&self, id: CellId) -> Option<&FilterViolation>

Returns the filter violation recorded for id as of the last full propagate() call, if any.

  • Postcondition: None if id has no filter, id’s filter’s last-checked value held, or no full propagate() has run since id was last a plain external write.
§Examples

See the graph example.

Source

pub fn filter_violated_cells(&self) -> impl Iterator<Item = CellId> + '_

Iterates cells whose filter is currently violated, as of the last full propagate() call.

  • Complexity: O(n) where n is the number of currently-violated filters.
§Examples

See the graph example.

Source

pub fn filter_violation_cells(&self) -> HashSet<CellId>

Returns the set of root cells currently determining a violated filter’s own value or any of its argument values, as of the last full propagate() call — the same “which upstream cells caused this” query requirement_contributing_cells/requirement_violation_cells already provide for Requirement.

  • Postcondition: empty if no filter is currently violated.
  • Complexity: O(sum of contributing_cells cost over every violated filter and its argument cells).
§Examples

See the graph example.

Source

pub fn cell_requirements(&self, id: CellId) -> Option<&[RequirementId]>

Returns the requirements attached to id, in attachment order.

Returns None if id is not a live cell in this sheet.

§Examples

See the graph example.

Source

pub fn requirement_cell(&self, id: RequirementId) -> Option<CellId>

Returns the cell requirement id is attached to.

Returns None if id is not a live requirement in this sheet.

§Examples

See the graph example.

Source

pub fn requirement_inputs(&self, id: RequirementId) -> Option<&[CellId]>

Returns the cells requirement id reads.

Returns None if id is not a live requirement in this sheet.

§Examples

See the graph example.

Source

pub fn cell_requirements_valid(&self, id: CellId) -> bool

Returns true if every requirement on id held as of the last propagate() call.

Returns false if no propagation has run yet. Also returns true for an id that is not a live cell in this sheet, since no requirement can have failed for a cell that doesn’t exist.

§Examples

See the graph example.

Source

pub fn violated_requirements( &self, id: CellId, ) -> impl Iterator<Item = RequirementId> + '_

Iterates the requirements on id that evaluated to false as of the last propagate() call.

  • Postcondition: empty if id’s requirements all held, id is not a live cell in this sheet, or no propagation has run yet.
§Examples

See the graph example.

Source

pub fn contributing_cells(&self, id: CellId) -> HashSet<CellId>

Returns the set of root cells that could determine id’s value for some choice of cell strengths, as of the last propagate() call.

A cell is a root candidate for current whenever some active relationship adjacent to current has a method producing it — not just the one method the current strengths happen to have selected: a different strength ordering could pick a different method of that same relationship, making any of its other cells the source instead. So every method (of every active relationship touching current) with current among its outputs contributes its inputs to the walk, not only the currently-selected one. A cell outside Sheet::is_forced’s pure-output classification contributes its own stored aspiration. This includes a self-referencing input even when a mandatory writer prevents the cell from remaining unclaimed: its seed can still depend on that aspiration.

Every visited cell is also checked against every conditional in the sheet: if any of that conditional’s branches (or its default) has a method whose outputs include the visited cell, the conditional’s match cell is added as a contributor too, and is itself traced recursively. This covers both an active producer that happens to belong to a conditional branch, and a cell with no active producer specifically because the branch that would define it isn’t the one currently selected (that absence is itself a fact controlled by the match cell, not an indication that the match cell is irrelevant).

A cell that can remain a source also contributes its dynamic filter arguments: the filter determines its effective value. Filters on outputs claimed in every acyclic assignment, including self-referencing outputs, only diagnose values and do not add value dependencies.

Eligibility searches use the candidate’s complete input/output relationship component within the last successful active set. That completed assignment witnesses feasibility of the independent components. Registered methods are never replaced or removed, so writes, appended structure and failed propagation preserve this witness; newly registered relationships stay outside these assignment searches until successful propagation publishes another active set. Filter arguments and potential conditional contributors still come from the current registered graph.

  • Postcondition: returns {id} if no propagation has run yet, or if id is not forced and no active or conditional relationship or dynamic filter could produce it.

  • Complexity: O(N · (R·M·K² + B·M·K)) where N is the number of cells reachable from id (including conditional match cells), R is the number of relationships adjacent to a visited cell, M is the maximum number of methods per relationship, K is the maximum input/output count per method, and B is the total number of branch/default relationships across all conditionals, plus the number of traversed filter argument edges. Each visited non-forced filtered cell with dynamic arguments that is not currently a source adds at most one exact eligibility search after expected linear traversal of that candidate’s component adjacency (including inactive adjacency entries). Each search takes expected O(T + U · (1 + A · K²)) time, where T is relationship storage slots scanned, A is active relationships in that component, and U counts that search’s recursive calls and examined method candidates. U is bounded by O(1 + M + … + M^A), including partial checks when M = 1; disconnected components do not multiply its search tree. Debug builds add O(G) validation during each component discovery, where G is prepared active relationships. Traversal storage is O(N + E) for visited cells and queued dependency edges E, plus visited component cells/relationships and O(1 + A · (1 + K)) auxiliary storage for one eligibility search. Repeated queries do not cache searches.

§Examples

See the graph example.

Source

pub fn requirement_contributing_cells( &self, id: RequirementId, ) -> HashSet<CellId>

Returns the union of Sheet::contributing_cells over requirement id’s own declared inputs.

Returns an empty set if id is not a live requirement in this sheet.

  • Complexity: The sum of Self::contributing_cells costs over the requirement’s inputs, with O(N) space for their union of N root cells.
§Examples

See the graph example.

Source

pub fn requirement_relevant_cells(&self) -> HashSet<CellId>

Returns the union of contributing_cells over every cell with at least one requirement — the set of cells currently determining at least one requirement-checked value, as of the last propagate() call.

  • Postcondition: empty if no cell in the sheet has any requirements.
  • Complexity: O(sum of contributing_cells cost over every cell with requirements).
§Examples

See the graph example.

Source

pub fn requirement_violation_cells(&self) -> HashSet<CellId>

Returns the union of requirement_contributing_cells over every requirement that evaluated false as of the last propagate() call, across every cell in the sheet.

  • Postcondition: empty if no requirement anywhere in the sheet currently fails.
  • Complexity: O(sum of requirement_contributing_cells cost over every violated requirement).
§Examples

See the graph example.

Source

pub fn write<T: Any + 'static>( &mut self, id: CellId, value: T, ) -> Result<(), Error>

Writes a value to a cell, incrementing the cell’s write-recency strength.

Each successful write increments a global monotonic counter and assigns the new value to cell.strength, so the most-recently-written cell always has the highest strength.

  • Postcondition: any pending derived override is cleared, so the written value is immediately visible via read().
  • Complexity: Expected O(1) validation and phase-membership work, plus O(A) when a claimed-cell write releases the final owners of prepared artifacts of total size A, excluding destruction of replaced values.
§Errors
  • Error::InvalidId — id is not a cell in this sheet.
  • Error::TypeMismatch — T does not match the cell’s registered TypeId.
  • Error::InvalidCellKind — id is Out-kind.
§Examples

See the graph example.

Source

pub fn read<T: Any + 'static>(&self, id: CellId) -> Result<&T, Error>

Returns a shared reference to the cell’s effective current value: its derived override if one exists, otherwise its source (last written) value.

§Errors
  • Error::InvalidId — id is not a cell in this sheet.
  • Error::TypeMismatch — T does not match the cell’s registered TypeId.
§Examples

See the graph example.

Source

pub fn source<T: Any + 'static>(&self, id: CellId) -> Result<&T, Error>

Returns the raw source slot: the last value written via write()/add_cell, ignoring any derived override produced by a self-referencing method or a conditionally forced relationship. For an ordinary (unshadowed) derived cell, propagate() writes straight into this same slot, so source() agrees with read(); the two diverge only for cells currently shadowed.

§Errors
  • Error::InvalidId — id is not a cell in this sheet.
  • Error::TypeMismatch — T does not match the cell’s registered TypeId.
§Examples
use adam_rs::Sheet;

let mut sheet = Sheet::new();
let a = sheet.add_cell(3_i32);
sheet.write(a, 8_i32).unwrap();
assert_eq!(*sheet.source::<i32>(a).unwrap(), 8);
Source

pub fn changed(&self) -> impl Iterator<Item = CellId> + '_

Iterates over cells updated during the most recent successful propagate() call.

This includes cells written by selected methods and cells that reverted to their source values because the relationship that had been shadowing them (self-referencing or conditionally forced) is no longer producing them this round (Phase 5), even though no method wrote to them this round. It does not attempt to compare old/new values for equality.

  • Complexity: O(n) where n is the number of changed cells.
§Examples

See the graph example.

Source

pub fn clear_changed(&mut self)

Clears the changed-cell set and resets each cell’s changed flag.

Call after processing the results of propagate().

  • Complexity: O(n) where n is the number of changed cells.
§Examples

See the graph example.

Source

pub fn validate(&mut self) -> Result<(), Error>

Validates static guard independence for the current sheet structure.

A filter’s argument cells and a conditional’s match cells must not depend on any cell governed by that filter or conditional in the static dependency graph. A successful call records the current structure as validated.

§Errors
  • Error::DependencyCycle — a guard edge lies on a cycle in the static dependency graph.
§Examples
use adam_rs::{Filter, Method, Sheet};

let mut sheet = Sheet::new();
let limit = sheet.add_cell(10_i32);
let value = sheet.add_cell(5_i32);
let copy = sheet.add_cell(0_i32);
sheet
    .add_relationship(vec![Method::from_fn_1_1(value, copy, |x: &i32| Ok(*x))])
    .unwrap();
sheet
    .add_filter(value, Filter::from_fn_1(limit, |v: &i32, hi: &i32| Ok((*v).min(*hi))))
    .unwrap();
sheet.validate().unwrap();
  • Complexity: O(1) when no structural mutation has happened since the last successful validation; otherwise O(V + E), where V is the number of cells and E is the number of static method and guard edges.
Source

pub fn cells(&self) -> impl Iterator<Item = CellId> + '_

Iterates all live cell IDs in the sheet.

  • Complexity: O(n) where n is the number of cells.
§Examples

See the graph example.

Source

pub fn relationships(&self) -> impl Iterator<Item = RelationshipId> + '_

Iterates all live relationship IDs in the sheet.

  • Complexity: O(n) where n is the number of relationships.
§Examples

See the graph example.

Source

pub fn cell_adj(&self, id: CellId) -> Option<&[RelationshipId]>

Returns the relationships adjacent to id.

Returns None if id is not a live cell in this sheet.

  • Complexity: O(1).
§Examples

See the graph example.

Source

pub fn relationship_adj(&self, id: RelationshipId) -> Option<&[CellId]>

Returns the cells adjacent to id (union across all methods).

Returns None if id is not a live relationship in this sheet.

  • Complexity: O(1).
§Examples

See the graph example.

Source

pub fn propagate(&mut self) -> Result<(), Error>

Updates the sheet using eligible prepared plans or newly selected methods.

Validates static guard independence before mutating state, then clears the changed-cell set from the previous propagate() call before staged planning. After propagation, call Sheet::changed to inspect which cells were updated, and Sheet::clear_changed when done.

Method, filter, conditional-expression, and requirement callbacks must be purely functional. There is no guarantee that any callback executes, or when or how often it executes; results may be reused or recomputed while preserving cell values and diagnostics. The phases below describe the current algorithm, not a callback invocation contract.

Retains at most one prepared unconditional plan and one prepared main plan, each with its own released sources and active relationships. Successful writes to released sources preserve that phase’s eligibility; writes to claimed cells (including self-referencing claimants) discard it. Filter reclamps do not claim released sources. Actual structural mutations discard both entries. Prepared plans retain structural seed recipes, not values from earlier calls.

Phase 0 — Staging: propagation starts from each cell’s source value, excluding every derived override from the previous round, but does not mutate live cells.

Phase 1 — Pre-plan: when conditionals exist, an eligible prepared unconditional plan is obtained or a new one is prepared. Its selected guard-prerequisite cone executes so derived guard values are current before branch evaluation. Unrelated filters remain deferred until the final active plan, after the relationships that produce their arguments.

Phase 2 — Conditional evaluation: each conditional’s match cell value is read and compared against branch keys; the active relationship set is built.

Phase 3 — General plan: an eligible prepared main plan is obtained for the active set, or the Adam algorithm selects and prepares a new one. Seed-cycle validation and method execution consume staged Phase 1 values. A callback already evaluated in Phase 1 is reused only when the final plan preserves its selected method, input producers, and output classification. A mismatched plan returns a conservative conflict rather than committing stale values. This boundary may reject a sheet even when another assignment could have avoided the mismatch; propagation reports the implicated sites instead of attempting that alternate assignment. A Phase 1 seed callback is likewise reused only when every input reads the same staged source version, recursive seed result, or accumulated value; otherwise propagation returns a conflict instead of reusing a stale seed.

Phase 4 — Commit and strength post-processing: after planning, seed validation, and staged method execution all succeed, staged writes are published atomically. Derived cells then receive low-order strengths in evaluation order, enforcing the stability invariant. A cell claimed self-referencingly keeps any live explicit strength instead, since its own written value is still the authority behind the result.

Phase 5 — Reversion change-tracking: a cell whose derived override existed before this round but wasn’t reclaimed by any method this round has effectively reverted to its source value (e.g. its forcing conditional went inactive); it is marked changed even though no method wrote to it this round.

Phase 6 — Requirement evaluation: every registered requirement is evaluated against current cell values, rebuilding last_requirement_violations from scratch, so Sheet::cell_requirements_valid and Sheet::violated_requirements reflect this round.

Filter failures remain diagnostics rather than propagation errors, and diagnostic results use current values.

  • Complexity: on a cache miss, prerequisite-cone indexing, traversal, and producer preparation take O(V + E) per selected plan, distinct from assignment matching. Cache hits omit this preparation, assignment matching, global strength sorting, and complete seed-elimination replay. Active-set comparison takes expected O(R) for R active relationships; a pending strength certificate takes O(C) for C cells. Current strength gates and local sibling sorts still run (O(S log S) comparisons for S siblings, with structural signature comparison costs). Fresh staged execution, seed evaluation, commit, and diagnostics retain their costs. Discarding final owners of prepared artifacts of total size A can take O(A).
§Errors
  • Error::DependencyCycle — a filter or conditional guard edge lies on a cycle in the static dependency graph.
  • Error::Conflict — no valid method assignment exists, or a pre-executed guard prerequisite is incompatible with the final selected plan.
  • Error::SeedCycle — sibling seed dependencies form a non-self cycle.
  • Error::MethodFailed — a method’s function returned an error, a method produced the wrong number of outputs, or a requirement’s function returned an error. A requirement error includes its governed cell as an error site.
  • Error::TypeMismatch — a method output’s runtime type does not match the cell’s registered type.
Source

pub fn selected_method(&self, rel: RelationshipId) -> Option<usize>

Returns the index of the method selected for rel in the last successful propagation.

Returns None if no propagation has run yet, rel is not in the cached plan, or rel was added after the last propagate() call.

  • Complexity: O(S) worst-case time for S completed execution steps; O(1) space.
§Examples

See the graph example.

Source

pub fn method_inputs( &self, rel: RelationshipId, idx: usize, ) -> Option<&[CellId]>

Returns the input cells of method idx in relationship rel.

Returns None if rel is not a live relationship or idx is out of bounds.

§Examples

See the graph example.

Source

pub fn method_outputs( &self, rel: RelationshipId, idx: usize, ) -> Option<&[CellId]>

Returns the output cells of method idx in relationship rel.

Returns None if rel is not a live relationship or idx is out of bounds.

§Examples

See the graph example.

Source

pub fn is_source(&self, id: CellId) -> bool

Returns true if id was not written by any selected method in the last successful propagation.

Returns false if no propagation has succeeded yet. This display query does not determine prepared-plan eligibility.

Cells absent from the completed plan, including newly added cells, return true.

  • Complexity: Expected O(1).
§Examples

See the graph example.

Source

pub fn source_cells( &self, results: &[CellId], ) -> impl Iterator<Item = CellId> + use<'_>

Iterates snapshot sources contributing to results in the last successful plan.

An empty results slice selects the entire sheet: unclaimed cells and outputs read by their own selected method. Otherwise, selects only those sources in the requested cells’ selected producer paths, including conforming filter arguments and conditional selectors governing those paths. Unselected methods’ inputs and diagnostic-only filter arguments do not contribute.

Each source appears once, in unspecified order, even when results repeat or share dependencies. Pure derived outputs and Out cells are excluded. Returns an empty iterator before any successful propagation. Like Self::is_source, classification describes the last successful plan; newly added non-Out cells count as unclaimed.

To capture a settled result, iterate after successful propagation and before further edits, reading effective values with Self::read, not the aspirations returned by Self::source. Clients own baseline comparison, relevance filtering, stable cell identity, and typed serialization.

Replay writes all captured values in any order as one batch before propagation. For a settled solution satisfying its relationships and filters, a compatible graph with matching uncaptured inputs reproduces the requested effective values (or all values when results is empty). Relationship methods must preserve an already-satisfied assignment, and self-referencing methods and filters must be idempotent; these caller contracts make the solution a fixed point even if replay selects different methods. No strengths or write history need to be captured. A snapshot does not preserve original aspirations, priority history, diagnostics, or behavior under subsequent edits, including spring-back.

  • Precondition: every result is a live cell belonging to this sheet.
  • Complexity: empty results take O(C + S + Σ(I × O)) traversal time and O(1) auxiliary space, for C cells, S selected steps, and each selected method’s I inputs and O outputs. Nonempty results add expected O(N + V + E + V × G) time and O(N + V + E) auxiliary space, for N requested results, V reachable value/producer pairs, E their dependency edges, and G the total size of the registered conditional graph. Does not copy cell values.
§Examples
use adam_rs::Sheet;
let mut sheet = Sheet::new();
let width = sheet.add_source(10_i32);
sheet.add_source(false);
sheet.propagate()?;
assert_eq!(sheet.source_cells(&[]).count(), 2);
let capture = sheet.source_cells(&[width])
    .map(|id| Ok((id, *sheet.read::<i32>(id)?)))
    .collect::<Result<Vec<_>, adam_rs::Error>>()?;
assert_eq!(capture, [(width, 10)]);
// Use host-defined names or schema keys, not live CellIds, for persistence.
Source

pub fn is_forced(&self, id: CellId) -> bool

Returns whether id belongs to the last successful plan’s forced pure-output set.

The planner intersects pure outputs across viable methods and eliminates alternatives that conflict with another relationship’s forced outputs until the classification stabilizes. A forced pure output’s producer does not read that cell as a self-referencing input.

A conditionally forced cell retains its pre-forcing priority and source aspiration for release; see the forcing outcomes.

This does not decide whether some assignment can leave the cell unclaimed. A mandatory self-referencing writer claims its output exclusively but remains outside this classification; its editable source aspiration can affect its seed.

Returns false if no propagation has run yet.

§Examples

See the graph example.

Source

pub fn forced_cells(&self) -> impl Iterator<Item = CellId> + '_

Iterates cells that are forced (see Sheet::is_forced) as of the last successful propagate() call.

  • Complexity: O(n) where n is the number of forced cells.
§Examples

See the graph example.

Source

pub fn is_relationship_forced(&self, id: RelationshipId) -> bool

Returns true if id had exactly one viable method as of the last successful propagate() call — the planner has no alternative method to choose for this relationship, regardless of cell strength.

Returns false if no propagation has run yet.

§Examples

See the graph example.

Source

pub fn forced_relationships(&self) -> impl Iterator<Item = RelationshipId> + '_

Iterates relationships that are forced (see Sheet::is_relationship_forced) as of the last successful propagate() call.

  • Complexity: O(n) where n is the number of forced relationships.
§Examples

See the graph example.

Source

pub fn conditionals(&self) -> impl Iterator<Item = ConditionalId> + '_

Iterates all live conditional IDs in the sheet.

  • Complexity: O(n) where n is the number of conditionals.
§Examples

See the graph example.

Source

pub fn out_cells(&self) -> impl Iterator<Item = CellId> + '_

Iterates all live Out-kind cells in the sheet.

  • Complexity: O(n) where n is the number of cells.
§Examples

See the graph example.

Source

pub fn conditional_match_cells(&self, id: ConditionalId) -> Option<&[CellId]>

Returns the match cells for conditional id: a single cell for a plain match subject, or every input of a MatchExpr match subject.

Returns None if id is not a live conditional in this sheet.

§Examples

See the graph example.

Source

pub fn conditional_branch_count(&self, id: ConditionalId) -> Option<usize>

Returns the number of named branches in conditional id.

Returns None if id is not a live conditional in this sheet.

§Examples

See the graph example.

Source

pub fn conditional_branch_relationships( &self, id: ConditionalId, branch: usize, ) -> Option<&[RelationshipId]>

Returns the relationship IDs for branch branch of conditional id.

Returns None if id is not a live conditional, or branch is out of bounds.

§Examples

See the graph example.

Source

pub fn conditional_default_relationships( &self, id: ConditionalId, ) -> Option<&[RelationshipId]>

Returns the default relationship IDs for conditional id.

These relationships are active when no named branch key matches the match cell. Returns None if id is not a live conditional in this sheet.

§Examples

See the graph example.

Source

pub fn conditional_active_branch( &self, id: ConditionalId, ) -> Result<Option<usize>, Error>

Returns the index of the currently matching branch for conditional id.

Evaluates branch keys against the match subject’s current value in definition order; returns the index of the first matching branch. Returns Ok(None) if no branch key matches (the default branch is active) or if id is not a live conditional.

§Errors
  • Error::MethodFailed — id is a live, expression-sourced conditional whose function returned an error. The original cause and ErrorSite::Conditional(id) identify the failing execution.

  • Complexity: O(B·K) where B = branches, K = keys per branch.

§Examples

See the graph example.

Trait Implementations§

Source§

impl Default for Sheet

Source§

fn default() -> Self

Returns Sheet::new().

Auto Trait Implementations§

§

impl !RefUnwindSafe for Sheet

§

impl !Send for Sheet

§

impl !Sync for Sheet

§

impl !UnwindSafe for Sheet

§

impl Freeze for Sheet

§

impl Unpin for Sheet

§

impl UnsafeUnpin for Sheet

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> 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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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.