Skip to main content

Graph

Struct Graph 

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

Graph container — Phase 1+ public API.

Holds an Arc<Core> internally plus an Arc<Mutex<GraphInner>> for namespace + mount-tree state. Cloning is a cheap refcount bump on both Arcs — pass Graph by value to threads (or share via Arc<Graph> when an outer reference count is needed).

Two clones of the same Graph share BOTH the dispatcher state AND the namespace. Mutations from one clone are visible to all clones.

Implementations§

Source§

impl Graph

Source

pub fn describe(&self) -> GraphDescribeOutput

Snapshot the graph’s topology + lifecycle state. JSON form only in this slice (see module docs).

Source§

impl Graph

Source

pub fn describe_reactive(&self, sink: DescribeSink) -> ReactiveDescribeHandle

Subscribe to live topology snapshots. The sink fires immediately with the current GraphDescribeOutput (push-on-subscribe per canonical §2.5.2 / R3.6.1) and then again with a fresh snapshot every time a node is added, removed, mounted, unmounted, or the graph is destroyed.

Returns a ReactiveDescribeHandle — dropping it unsubscribes.

This is the reactive: true mode from canonical §3.6.1. The reactive: "diff" (changeset) mode is deferred to Phase 14.

Note: set_deps topology changes fire via Core’s topology primitive, not this Graph-level namespace hook. If callers also need set_deps notifications, compose with graphrefly_core::Core::subscribe_topology.

The sink captures only a Weak reference to the graph’s inner state, so the namespace_sinks → sink → Graph → namespace_sinks Arc cycle is broken at the sink edge (see P6 in the Slice F /qa closing notes).

Source§

impl Graph

Source

pub fn new(name: impl Into<String>, binding: Arc<dyn BindingBoundary>) -> Self

Construct a named, empty root graph wired to the given binding.

name becomes the graph’s identity for describe() output and ancestors(). May contain colons (":"), but the double-colon path separator ("::") is reserved; use Graph::is_valid_name to pre-check user input.

Source

pub fn with_existing_core(name: impl Into<String>, core: Core) -> Self

Construct a fresh root Graph wrapping an existing Core. Used by binding crates (napi-rs, pyo3, wasm) where the same Core is shared between a Graph and direct binding-side dispatch (BenchOperators::register_*, etc.) so the namespace and the operator surface see the same node ids.

Sister method to Self::new; the difference is that new constructs a fresh Core from a binding, while this one accepts a Core the caller already owns (typically cloned from BenchCore).

Source

pub fn name(&self) -> String

The graph’s name as set at construction (or via mount / mount_new).

Source

pub fn core(&self) -> &Core

Borrow the underlying Core — the M1 dispatcher. Useful when you need a Core-level method that hasn’t yet been surfaced on Graph. Phase 4+ patterns commonly hold onto the Core directly.

Source

pub fn is_valid_name(name: &str) -> bool

Whether name is a legal local node/subgraph name (no ::).

Source

pub fn add( &self, node_id: NodeId, name: impl Into<String>, ) -> Result<NodeId, NameError>

Register an existing node_id under name in this graph’s namespace. The node is assumed already-registered with the underlying Core (via Graph::core or sugar constructors).

Returns the same node_id for chaining. Returns NameError::Destroyed if the graph has been Self::destroyed (symmetric with crate::MountError::Destroyed).

Source

pub fn node(&self, path: &str) -> NodeId

Resolve a path to a NodeId. Panics if missing — use Self::try_resolve for the non-panicking variant.

Paths use :: separators: "validate" (local), "payment::validate" (one mount level), "system::payment::validate" (two levels).

§Panics

Panics if any path segment is unknown.

Source

pub fn try_resolve(&self, path: &str) -> Option<NodeId>

Non-panicking variant of Self::node.

Source

pub fn name_of(&self, node_id: NodeId) -> Option<String>

Reverse lookup: returns the local name for a node_id, or None if the node is unnamed in this graph (it may still be registered in Core — Graph::core().node_ids() enumerates all of them).

Source

pub fn node_count(&self) -> usize

Number of named nodes in this graph (excludes mounted children’s nodes, and excludes Core-only unnamed nodes). Recursive count is available by summing across Self::child_names + per-child node_count().

Source

pub fn node_names(&self) -> Vec<String>

Snapshot of local node names in insertion order.

Source

pub fn child_names(&self) -> Vec<String>

Snapshot of mounted child names in insertion order.

Source

pub fn is_destroyed(&self) -> bool

Returns true after Self::destroy has been called.

Source

pub fn state( &self, name: impl Into<String>, initial: Option<HandleId>, ) -> Result<NodeId, NameError>

Register a state node under name. initial of None starts sentinel; Some(h) pre-populates the cache. Returns the underlying NodeId.

§Panics

Structurally never panics — state-node registration has no reachable graphrefly_core::RegisterError variants for any caller-supplied input (state nodes have no deps and no operator scratch). The .expect() is present to satisfy the typed-error surface from Slice H; the Result return covers NameError (namespace conflicts) only.

Source

pub fn derived( &self, name: impl Into<String>, deps: &[NodeId], fn_id: FnId, equals: EqualsMode, ) -> Result<NodeId, NameError>

Register a static-derived node — fn fires on every dep change with all deps tracked. Defaults to gated first-run (R2.5.3); use [Self::derived_with_partial] for the partial-mode variant (D011 / R5.4).

§Panics

Panics if any element of deps is not a registered node id, or if a dep is terminal and not resubscribable. The Result return covers NameError (namespace conflicts); construction-time errors at the Core layer (graphrefly_core::RegisterError) are caller-contract violations and surface as panics.

Source

pub fn dynamic( &self, name: impl Into<String>, deps: &[NodeId], fn_id: FnId, equals: EqualsMode, ) -> Result<NodeId, NameError>

Register a dynamic-derived node — fn declares which dep indices it actually read this run. Defaults to gated first-run (R2.5.3).

§Panics

Panics if any element of deps is not a registered node id, or if a dep is terminal and not resubscribable. The Result return covers NameError (namespace conflicts); construction-time errors at the Core layer (graphrefly_core::RegisterError) are caller-contract violations and surface as panics.

Source

pub fn set(&self, name: &str, handle: HandleId)

Emit a value on a named state node.

§Panics

Panics if name does not resolve to a node.

Source

pub fn get(&self, name: &str) -> HandleId

Read the cached value of a named node. Returns graphrefly_core::NO_HANDLE if sentinel.

§Panics

Panics if name does not resolve.

Source

pub fn invalidate_by_name(&self, name: &str)

Clear the cache of a named node and cascade [INVALIDATE].

§Panics

Panics if name does not resolve.

Source

pub fn complete_by_name(&self, name: &str)

Mark a named node terminal with COMPLETE.

§Panics

Panics if name does not resolve.

Source

pub fn error_by_name(&self, name: &str, error_handle: HandleId)

Mark a named node terminal with ERROR.

§Panics

Panics if name does not resolve.

Source

pub fn remove(&self, name: &str) -> Result<GraphRemoveAudit, RemoveError>

Remove a named node OR mounted subgraph. Fires [TEARDOWN] on the node (which cascades to meta children per R1.3.9.d). For subgraphs, delegates to Self::unmount. Returns GraphRemoveAudit describing what was removed.

Sinks observing TEARDOWN can resolve the node’s name via Graph::name_of / Graph::try_resolve for the duration of the cascade — namespace clearing happens AFTER the teardown returns (R3.2.3 / R3.7.3 ordering, mirroring destroy()).

Returns Err(RemoveError::NotFound) if name is unknown (neither a local node nor a mounted subgraph). Returns Err(RemoveError::Destroyed) if the graph (or, in the subgraph branch, an ancestor in the unmount path) has been destroyed.

Source

pub fn edges(&self, recursive: bool) -> Vec<(String, String)>

Derive edges from the current topology. Returns [from, to] pairs where both names are local namespace entries (or _anon_<id> for unnamed Core-only deps — including deps living in sibling graphs that share this graph’s Core but are not in this graph’s local namespace).

When recursive is true, recurses into mounted subgraphs and qualifies names with :: path separators.

Source

pub fn subscribe(&self, node_id: NodeId, sink: Sink) -> Subscription

Subscribe a sink. Returns a Subscription handle — dropping it unsubscribes. See graphrefly_core::Core::subscribe for full handshake semantics.

Source

pub fn emit(&self, node_id: NodeId, new_handle: HandleId)

Emit a value on a state node.

Source

pub fn cache_of(&self, node_id: NodeId) -> HandleId

Read a node’s current cache. Returns graphrefly_core::NO_HANDLE if sentinel.

Source

pub fn has_fired_once(&self, node_id: NodeId) -> bool

Whether the node’s fn has fired at least once (compute) OR it has had a non-sentinel value (state).

Source

pub fn complete(&self, node_id: NodeId)

Mark the node terminal with COMPLETE.

Source

pub fn error(&self, node_id: NodeId, error_handle: HandleId)

Mark the node terminal with ERROR.

Source

pub fn teardown(&self, node_id: NodeId)

Tear the node down (R2.6.4).

Source

pub fn invalidate(&self, node_id: NodeId)

Clear the node’s cache and cascade [INVALIDATE] to dependents.

Source

pub fn pause(&self, node_id: NodeId, lock_id: LockId) -> Result<(), PauseError>

Acquire a pause lock.

Source

pub fn resume( &self, node_id: NodeId, lock_id: LockId, ) -> Result<Option<ResumeReport>, PauseError>

Release a pause lock.

Source

pub fn alloc_lock_id(&self) -> LockId

Allocate a fresh LockId.

Source

pub fn set_deps( &self, n: NodeId, new_deps: &[NodeId], ) -> Result<(), SetDepsError>

Atomically rewire a node’s deps.

§Hazards

Re-entrant set_deps from inside the firing node’s own fn corrupts Dynamic tracked indices (D1 in ~/src/graphrefly-rs/docs/porting-deferred.md). If a Dynamic node n’s fn captures a Graph clone and re-enters Graph::set_deps(n, ...) from inside its own BindingBoundary::invoke_fn call, the dep ordering is rewritten while the fn-result tracked: Some([...]) is being staged against the OLD ordering. Phase 3 of fire_fn then stores those stale indices into rec.tracked against the NEW dep vector — pointing at different upstream nodes than the fn intended to track.

Acceptable v1: most set_deps callers are external orchestrators, not the firing node itself. The structural fix (a thread-local “currently firing” stack with SetDepsError::ReentrantOnFiringNode) lifts in a later slice.

Source

pub fn set_resubscribable(&self, node_id: NodeId, resubscribable: bool)

Mark the node as resubscribable (R2.2.7).

Source

pub fn add_meta_companion(&self, parent: NodeId, companion: NodeId)

Attach companion as a meta companion of parent (R1.3.9.d).

Source

pub fn batch<F: FnOnce()>(&self, f: F)

Coalesce multiple emissions into a single wave.

Source

pub fn signal(&self, kind: SignalKind)

General broadcast (canonical R3.7.1). Sends kind to every named node in this graph plus recursively into mounted children.

Supported kinds:

  • SignalKind::Invalidate — with meta filtering per R3.7.2.
  • SignalKind::Pause(lock_id) — pause every named node.
  • SignalKind::Resume(lock_id) — resume every named node.

Idempotent on a destroyed graph (no-op).

Source

pub fn signal_invalidate(&self)

Broadcast [INVALIDATE] to every named node in this graph plus recursively into mounted children. Meta companions (R1.3.9.d / R2.3.3) are filtered out per canonical R3.7.2: their cached values are preserved across graph-wide invalidation.

Filter happens at the graph layer because the Core invalidate cascade does NOT skip meta children — it walks every consumer in children. The graph-layer filter walks the namespace, builds a “set of node ids that are meta-companion-of-some-other-named-node”, and excludes them from the iterate-and-invalidate loop. Direct Core::invalidate(meta_id) still wipes a meta’s cache — the filter applies only to this graph-layer broadcast.

Idempotent on a destroyed graph (no-op).

Source

pub fn destroy(&self)

Tear down every named node in this graph plus recursively into mounted children, then clear namespace + mount-tree state.

The underlying Core is NOT dropped — other clones of this graph (or the Core itself) may still be alive. Only namespace

  • mount tree are cleared.

Cascade order (canonical R3.7.3 — “After cascade, graph internal registries are cleared”). Mark destroyed = true to refuse new mutations, snapshot ids + children under the lock, drop the lock, recurse into children, fire core.teardown(id) per own id (sinks see TEARDOWN with the namespace still populated — Graph::name_of resolves), THEN reacquire the lock and clear the namespace. Without this order, sinks that look up names during the TEARDOWN cascade would see None.

Source

pub fn mount( &self, name: impl Into<String>, child: Graph, ) -> Result<Graph, MountError>

Embed an existing child graph as a subgraph under name. child must share this graph’s Core (cross-Core mount is post-M6 per session-doc Open Question 1).

Returns the registered child for chaining.

Source

pub fn mount_new(&self, name: impl Into<String>) -> Result<Graph, MountError>

Create an empty subgraph sharing this graph’s Core, mounted under name.

Source

pub fn mount_with<F: FnOnce(&Graph)>( &self, name: impl Into<String>, builder: F, ) -> Result<Graph, MountError>

Builder pattern: create an empty subgraph, run builder against it, then return the registered subgraph.

Source

pub fn unmount(&self, name: &str) -> Result<GraphRemoveAudit, MountError>

Detach a previously-mounted subgraph. Tears it down (TEARDOWN cascade across the child’s nodes + recursively into the child’s mounts) and returns a GraphRemoveAudit describing what was removed.

Source

pub fn ancestors(&self, include_self: bool) -> Vec<Graph>

Parent chain (root last). include_self = true prepends this graph; false returns ancestors only.

Source§

impl Graph

Source

pub fn observe(&self, path: &str) -> GraphObserveOne

Tap a single node’s downstream message stream.

§Panics

Panics if path doesn’t resolve. Use Graph::try_resolve

  • a manual subscribe if non-panicking is required.
Source

pub fn observe_all(&self) -> GraphObserveAll

Tap every named node in this graph.

§Snapshot semantics

The returned handle subscribes against the namespace at the moment subscribe() is called. Nodes named AFTER that call are not auto-subscribed. Use Self::observe_all_reactive for dynamic membership.

Source

pub fn observe_all_reactive(&self) -> GraphObserveAllReactive

Tap every named node AND auto-subscribe late-added nodes.

Like Self::observe_all but subscribes to topology changes so that nodes registered AFTER the initial subscribe() call are automatically picked up. Dropping the returned handle unsubscribes all fan-out sinks AND the topology listener.

Trait Implementations§

Source§

impl Clone for Graph

Source§

fn clone(&self) -> Graph

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 Graph

Source§

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

Compact Debug summary — name + counts. Avoids printing the full namespace map (which would lock + clone strings each call, surprising under dbg!()). Use Graph::describe for a full snapshot.

Auto Trait Implementations§

§

impl Freeze for Graph

§

impl !RefUnwindSafe for Graph

§

impl Send for Graph

§

impl Sync for Graph

§

impl Unpin for Graph

§

impl UnsafeUnpin for Graph

§

impl !UnwindSafe for Graph

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.