pub struct GraphObserveOne { /* private fields */ }Expand description
Single-node observe handle (canonical §3.6.2).
D246: holds a Core-free Graph; &Core is passed per call.
§Two coexisting message-injection shapes (D298, 2026-05-26)
This impl exposes BOTH the canonical up(messages) open-vocab
shape AND per-tier typed methods. They have different semantics
and are NOT sugar wrappers for each other. Both shapes are
supported as first-class public API; users pick based on intent.
-
Canonical R3.6.2 —
Self::up(messages)— send messages UPSTREAM toward the observed node’s sources. Routes throughCore::up, which iterates each dep and dispatches the message-specific upstream action (Pause→ pause each dep;Resume→ resume each dep;Invalidate→ recursive plain- forward to leaves per R1.4.2;Teardown→ teardown each dep). For a leaf node with no deps (e.g., a state node),up()is a no-op — there is no upstream. Open message vocabulary mirrors pure-tsNode.up(messages)(core/node.ts:1430). -
Direct typed methods —
Self::pause/Self::resume/Self::invalidate— mutate the OBSERVED NODE directly (not its upstream).observer.pause(lock)callsCore::pause(self.node_id, lock)and pauses the observed node itself; for a leaf state node, this DOES pause it. Rust-idiomatic typed-arg shortcuts for the common “pause/resume/invalidate the thing I’m observing” pattern. Non-allocating (noVec<Message>heap churn on the control plane). The collaboration directive infeedback_no_imperativeuser memory favors these intent-named typed calls over message-injection vocabulary when the operation IS “act on this node directly.”
Use up(messages) for canonical upstream-injection (matches TS
pure-ts wire shape; required for cross-impl parity scenarios
asserting canonical R3.6.2 behavior). Use typed methods for
direct-node ergonomic mutation. Same GraphObserveOne handle
exposes both.
§Decision provenance
- Q1 user-locked Option 2 (canonical primary + typed sugar
coexisting). Override of D196 (consumer-pressure gate) per the
/porting-to-rs clear all the perf items and the deferred items. regardless if they need a valid consumer demanddirective. - D298 (
~/src/graphrefly-ts/docs/rust-port-decisions.md).
Implementations§
Source§impl GraphObserveOne
impl GraphObserveOne
Sourcepub fn subscribe(&self, core: &Core, sink: Sink) -> ObserveSub
pub fn subscribe(&self, core: &Core, sink: Sink) -> ObserveSub
Subscribe a sink. Returns an ObserveSub id pair — detach
owner-invoked (D246 rule 3).
Sourcepub fn resume(
&self,
core: &Core,
lock: LockId,
) -> Result<Option<ResumeReport>, PauseError>
pub fn resume( &self, core: &Core, lock: LockId, ) -> Result<Option<ResumeReport>, PauseError>
Sourcepub fn invalidate(&self, core: &Core)
pub fn invalidate(&self, core: &Core)
Send [INVALIDATE] upstream.
Sourcepub fn up(&self, core: &Core, messages: &[Message]) -> Result<(), UpError>
pub fn up(&self, core: &Core, messages: &[Message]) -> Result<(), UpError>
Send messages upstream toward the observed node’s sources
(canonical R3.6.2 up(messages) shape — D298, 2026-05-26).
Each message is dispatched via Core::up to the observed
node, which then forwards per the tier-specific upstream
routing:
Message::Pause(lock)→Core::pauseon each dep.Message::Resume(lock)→Core::resumeon each dep.Message::Invalidate→ recursive plain-forward to leaf sources per R1.4.2 (no self-process at intermediates).Message::Teardown→Core::teardowncascade on each dep.Message::Start/Message::Dirty→ no-op upstream per the routing table inCore::up.
For a leaf node (no deps — e.g., a state node) up() is a
no-op. Use the typed Self::pause / Self::resume /
Self::invalidate methods if the intent is to mutate the
observed node directly.
Fails on the first message that errors; subsequent messages
are NOT dispatched. Empty messages is Ok(()).
§Errors
UpError::UnknownNode— observed node not registered (only reachable ifteardownremoved it afterobserve()).UpError::TierForbidden—messagescontains a tier-3 (Data/Resolved) or tier-5 (Complete/Error) variant; these are downstream-only per R1.4.1.