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
impl Graph
Sourcepub fn describe(&self) -> GraphDescribeOutput
pub fn describe(&self) -> GraphDescribeOutput
Snapshot the graph’s topology + lifecycle state. JSON form only in this slice (see module docs).
Source§impl Graph
impl Graph
Sourcepub fn describe_reactive(&self, sink: DescribeSink) -> ReactiveDescribeHandle
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
impl Graph
Sourcepub fn new(name: impl Into<String>, binding: Arc<dyn BindingBoundary>) -> Self
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.
Sourcepub fn with_existing_core(name: impl Into<String>, core: Core) -> Self
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).
Sourcepub fn name(&self) -> String
pub fn name(&self) -> String
The graph’s name as set at construction (or via mount / mount_new).
Sourcepub fn core(&self) -> &Core
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.
Sourcepub fn is_valid_name(name: &str) -> bool
pub fn is_valid_name(name: &str) -> bool
Whether name is a legal local node/subgraph name (no ::).
Sourcepub fn add(
&self,
node_id: NodeId,
name: impl Into<String>,
) -> Result<NodeId, NameError>
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).
Sourcepub fn node(&self, path: &str) -> NodeId
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.
Sourcepub fn try_resolve(&self, path: &str) -> Option<NodeId>
pub fn try_resolve(&self, path: &str) -> Option<NodeId>
Non-panicking variant of Self::node.
Sourcepub fn name_of(&self, node_id: NodeId) -> Option<String>
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).
Sourcepub fn node_count(&self) -> usize
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().
Sourcepub fn node_names(&self) -> Vec<String>
pub fn node_names(&self) -> Vec<String>
Snapshot of local node names in insertion order.
Sourcepub fn child_names(&self) -> Vec<String>
pub fn child_names(&self) -> Vec<String>
Snapshot of mounted child names in insertion order.
Sourcepub fn is_destroyed(&self) -> bool
pub fn is_destroyed(&self) -> bool
Returns true after Self::destroy has been called.
Sourcepub fn state(
&self,
name: impl Into<String>,
initial: Option<HandleId>,
) -> Result<NodeId, NameError>
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.
Sourcepub fn derived(
&self,
name: impl Into<String>,
deps: &[NodeId],
fn_id: FnId,
equals: EqualsMode,
) -> Result<NodeId, NameError>
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.
Sourcepub fn dynamic(
&self,
name: impl Into<String>,
deps: &[NodeId],
fn_id: FnId,
equals: EqualsMode,
) -> Result<NodeId, NameError>
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.
Sourcepub fn get(&self, name: &str) -> HandleId
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.
Sourcepub fn invalidate_by_name(&self, name: &str)
pub fn invalidate_by_name(&self, name: &str)
Sourcepub fn complete_by_name(&self, name: &str)
pub fn complete_by_name(&self, name: &str)
Sourcepub fn error_by_name(&self, name: &str, error_handle: HandleId)
pub fn error_by_name(&self, name: &str, error_handle: HandleId)
Sourcepub fn remove(&self, name: &str) -> Result<GraphRemoveAudit, RemoveError>
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.
Sourcepub fn edges(&self, recursive: bool) -> Vec<(String, String)>
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.
Sourcepub fn subscribe(&self, node_id: NodeId, sink: Sink) -> Subscription
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.
Sourcepub fn cache_of(&self, node_id: NodeId) -> HandleId
pub fn cache_of(&self, node_id: NodeId) -> HandleId
Read a node’s current cache. Returns
graphrefly_core::NO_HANDLE if sentinel.
Sourcepub fn has_fired_once(&self, node_id: NodeId) -> bool
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).
Sourcepub fn error(&self, node_id: NodeId, error_handle: HandleId)
pub fn error(&self, node_id: NodeId, error_handle: HandleId)
Mark the node terminal with ERROR.
Sourcepub fn invalidate(&self, node_id: NodeId)
pub fn invalidate(&self, node_id: NodeId)
Clear the node’s cache and cascade [INVALIDATE] to dependents.
Sourcepub fn pause(&self, node_id: NodeId, lock_id: LockId) -> Result<(), PauseError>
pub fn pause(&self, node_id: NodeId, lock_id: LockId) -> Result<(), PauseError>
Acquire a pause lock.
Sourcepub fn resume(
&self,
node_id: NodeId,
lock_id: LockId,
) -> Result<Option<ResumeReport>, PauseError>
pub fn resume( &self, node_id: NodeId, lock_id: LockId, ) -> Result<Option<ResumeReport>, PauseError>
Release a pause lock.
Sourcepub fn alloc_lock_id(&self) -> LockId
pub fn alloc_lock_id(&self) -> LockId
Allocate a fresh LockId.
Sourcepub fn set_deps(
&self,
n: NodeId,
new_deps: &[NodeId],
) -> Result<(), SetDepsError>
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.
Sourcepub fn set_resubscribable(&self, node_id: NodeId, resubscribable: bool)
pub fn set_resubscribable(&self, node_id: NodeId, resubscribable: bool)
Mark the node as resubscribable (R2.2.7).
Sourcepub fn add_meta_companion(&self, parent: NodeId, companion: NodeId)
pub fn add_meta_companion(&self, parent: NodeId, companion: NodeId)
Attach companion as a meta companion of parent (R1.3.9.d).
Sourcepub fn signal(&self, kind: SignalKind)
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).
Sourcepub fn signal_invalidate(&self)
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).
Sourcepub fn destroy(&self)
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.
Sourcepub fn mount(
&self,
name: impl Into<String>,
child: Graph,
) -> Result<Graph, MountError>
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.
Sourcepub fn mount_new(&self, name: impl Into<String>) -> Result<Graph, MountError>
pub fn mount_new(&self, name: impl Into<String>) -> Result<Graph, MountError>
Create an empty subgraph sharing this graph’s Core, mounted
under name.
Sourcepub fn mount_with<F: FnOnce(&Graph)>(
&self,
name: impl Into<String>,
builder: F,
) -> Result<Graph, MountError>
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.
Sourcepub fn unmount(&self, name: &str) -> Result<GraphRemoveAudit, MountError>
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§impl Graph
impl Graph
Sourcepub fn observe(&self, path: &str) -> GraphObserveOne
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.
Sourcepub fn observe_all(&self) -> GraphObserveAll
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.
Sourcepub fn observe_all_reactive(&self) -> GraphObserveAllReactive
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.