seq_runtime/weave.rs
1//! Weave operations for generator/coroutine-style concurrency
2//!
3//! A "weave" is a strand that can yield values back to its caller and be resumed.
4//! Unlike regular strands (fire-and-forget), weaves allow bidirectional communication
5//! with structured yield/resume semantics.
6//!
7//! ## Zero-Mutex Design
8//!
9//! Like channels, weaves pass their communication handles directly on the stack.
10//! There is NO global registry and NO mutex contention. The weave context travels
11//! with the stack values.
12//!
13//! ## API
14//!
15//! - `strand.weave`: ( Quotation -- WeaveHandle ) - creates a woven strand, returns handle
16//! - `strand.resume`: ( WeaveHandle a -- WeaveHandle a Bool ) - resume with value
17//! - `strand.weave-cancel`: ( WeaveHandle -- ) - cancel a weave and release its resources
18//! - `yield`: ( WeaveCtx a -- WeaveCtx a ) - yield a value (only valid inside weave)
19//!
20//! ## Architecture
21//!
22//! Each weave has two internal channels that travel as values:
23//! - The WeaveHandle (returned to caller) contains the yield_chan for receiving
24//! - The WeaveCtx (on weave's stack) contains both channels for yield to use
25//!
26//! Flow:
27//! 1. strand.weave creates channels, spawns coroutine with WeaveCtx on stack
28//! 2. The coroutine waits on resume_chan for the first resume value
29//! 3. Caller calls strand.resume with WeaveHandle, sending value to resume_chan
30//! 4. Coroutine wakes, receives value, runs until yield
31//! 5. yield uses WeaveCtx to send/receive, returns with new resume value
32//! 6. When quotation returns, WeaveCtx signals completion
33//!
34//! ## Resource Management
35//!
36//! **Best practice:** Weaves should either be resumed until completion OR explicitly
37//! cancelled with `strand.weave-cancel` to cleanly release resources.
38//!
39//! However, dropping a WeaveHandle without doing either is safe - the program will
40//! still exit normally. The un-resumed weave is "dormant" (not counted as an active
41//! strand) until its first resume, so it won't block program shutdown. The dormant
42//! coroutine will be cleaned up when the program exits.
43//!
44//! **Resource implications of dormant weaves:** Each dormant weave consumes memory
45//! for its coroutine stack (default 128KB, configurable via SEQ_STACK_SIZE) until
46//! program exit. For short-lived programs or REPL sessions this is fine, but
47//! long-running servers should properly cancel weaves to avoid accumulating memory.
48//!
49//! Proper cleanup options:
50//!
51//! **Option 1: Resume until completion**
52//! ```seq
53//! [ generator-body ] strand.weave # Create weave
54//! 0 strand.resume # Resume until...
55//! if # ...has_more is false
56//! # process value...
57//! drop 0 strand.resume # Keep resuming
58//! else
59//! drop drop # Clean up when done
60//! then
61//! ```
62//!
63//! **Option 2: Explicit cancellation**
64//! ```seq
65//! [ generator-body ] strand.weave # Create weave
66//! 0 strand.resume # Get first value
67//! if
68//! drop # We only needed the first value
69//! strand.weave-cancel # Cancel and clean up
70//! else
71//! drop drop
72//! then
73//! ```
74//!
75//! ## Implementation Notes
76//!
77//! Control flow (completion, cancellation) is handled via a type-safe `WeaveMessage`
78//! enum rather than sentinel values. This means **any** Value can be safely yielded
79//! and resumed, including edge cases like `i64::MIN`.
80//!
81//! ## Error Handling
82//!
83//! All weave functions are `extern "C"` and never panic (panicking across FFI is UB).
84//!
85//! - **Type mismatches** (e.g., `strand.resume` without a WeaveHandle): These indicate
86//! a compiler bug or memory corruption. The function prints an error to stderr and
87//! calls `std::process::abort()` to terminate immediately.
88//!
89//! - **Channel errors in `yield`**: If channels close unexpectedly while a coroutine
90//! is yielding, the coroutine cleans up and blocks forever. The main program can
91//! still terminate normally since the strand is marked as completed.
92//!
93//! - **Channel errors in `resume`**: Returns `(handle, placeholder, false)` to indicate
94//! the weave has completed or failed. The caller should check the Bool result.
95//!
96//! ## Module Layout
97//!
98//! Per-concern sub-modules:
99//! - `spawn` — `patch_seq_weave` (creator, ~240 L with both Quotation and Closure paths)
100//! - `resume` — `patch_seq_resume` + `patch_seq_weave_cancel` (caller-side)
101//! - `yield_op` — `patch_seq_yield` (weave-side)
102//! - `strand_lifecycle` — shared `cleanup_strand` / `block_forever` helpers
103
104mod resume;
105mod spawn;
106mod strand_lifecycle;
107mod yield_op;
108
109pub use resume::{patch_seq_resume, patch_seq_weave_cancel};
110pub use spawn::patch_seq_weave;
111pub use yield_op::patch_seq_yield;
112
113// Public re-exports
114pub use patch_seq_resume as resume;
115pub use patch_seq_weave as weave;
116pub use patch_seq_weave_cancel as weave_cancel;
117pub use patch_seq_yield as weave_yield;
118
119#[cfg(test)]
120mod tests;