Skip to main content

wasm4pm_compat/
workflow.rs

1//! Parallel Workflow Typestate Model.
2//!
3//! Defined in [workflow.rs](file:///Users/sac/wasm4pm-compat/src/workflow.rs).
4//!
5//! This module provides a compile-time typestate workflow tracking mechanism for checking
6//! process flow topology, transitions, and cancellation branches.
7//!
8//! ## Representation
9//! All types in this module, including [`crate::workflow::BranchToken`], [`crate::workflow::ParallelWorkflow`], [`crate::workflow::JoinPoint`],
10//! and the state markers, are zero-sized types (0 bytes). They use [`core::marker::PhantomData`] to carry compile-time
11//! structural and generic type information without runtime overhead.
12//!
13//! ## Structure-only
14//! This module does not execute code, spawn threads, or run tasks. It acts strictly as a static shape and
15//! transition validator to verify that branches are correctly initialized, progressed, canceled, or joined.
16//!
17//! ## Graduation
18//! While this module ensures correct compile-time workflow structures, it graduates to the dynamic execution,
19//! event broker, and orchestrator subsystems of `wasm4pm`.
20
21use std::marker::PhantomData;
22
23// =============================================================================
24// 1. Zero-Sized State Markers representing the lifecycle of workflow branches
25// =============================================================================
26
27/// The branch is initialized but has not started executing.
28///
29/// ### Representation
30/// A zero-sized state marker [`Pending`](file:///Users/sac/wasm4pm-compat/src/workflow.rs) that occupies 0 bytes of memory.
31///
32/// ### Structure-only
33/// Represents a static state indicating a branch is ready to start. It contains no runtime status,
34/// data values, or execution logic.
35///
36/// ### Graduation
37/// In the full `wasm4pm` execution engine, a pending task is placed in a scheduler queue for dynamic dispatch.
38/// In this compat crate, it is modeled purely as a compile-time static type parameter.
39pub struct Pending;
40
41/// The branch is currently active and executing.
42///
43/// ### Representation
44/// A zero-sized state marker [`Running`](file:///Users/sac/wasm4pm-compat/src/workflow.rs) that occupies 0 bytes of memory.
45///
46/// ### Structure-only
47/// Represents a static state indicating a branch is currently running. It holds no association with threads,
48/// tasks, futures, or async runtimes.
49///
50/// ### Graduation
51/// The `wasm4pm` engine tracks running tasks dynamically via host-managed event states and logs.
52/// Here, it is represented as a static compile-time type parameter.
53pub struct Running;
54
55/// The branch completed its task successfully.
56///
57/// ### Representation
58/// A zero-sized state marker [`Completed`](file:///Users/sac/wasm4pm-compat/src/workflow.rs) that occupies 0 bytes of memory.
59///
60/// ### Structure-only
61/// Represents a static state indicating successful execution completion of a branch. It does not store
62/// task results, return values, or logs.
63///
64/// ### Graduation
65/// In `wasm4pm`, branch completion generates trace events and triggers downstream control flows dynamically.
66/// In this compat layer, it statically proves path completion for compile-time checking.
67pub struct Completed;
68
69/// The branch was canceled by a concurrent cancellation region.
70///
71/// ### Representation
72/// A zero-sized state marker [`Canceled`](file:///Users/sac/wasm4pm-compat/src/workflow.rs) that occupies 0 bytes of memory.
73///
74/// ### Structure-only
75/// Represents a static state indicating a branch was canceled. It carries no cancellation error context
76/// or cancellation signals.
77///
78/// ### Graduation
79/// In `wasm4pm`, cancellation propagates dynamically via signals to active tasks, aborting execution.
80/// Here, cancellation is a static transition that consumes the token, preventing future completion.
81pub struct Canceled;
82
83/// A marker trait to constrain allowed typestate markers.
84///
85/// ### Representation
86/// A marker trait [`BranchState`](file:///Users/sac/wasm4pm-compat/src/workflow.rs) with no runtime footprint, generic parameters, or data fields.
87///
88/// ### Structure-only
89/// Used purely as a compile-time type boundary to restrict state parameters to [`Pending`], [`Running`],
90/// [`Completed`], or [`Canceled`]. It provides no functional logic.
91///
92/// ### Graduation
93/// During graduation to the `wasm4pm` execution engine, these compile-time constraints map to dynamic,
94/// schema-validated state transition policies.
95pub trait BranchState {}
96impl BranchState for Pending {}
97impl BranchState for Running {}
98impl BranchState for Completed {}
99impl BranchState for Canceled {}
100
101// =============================================================================
102// 2. Linear Branch Token
103// =============================================================================
104
105/// An ownership-bearing token representing a specific execution path.
106/// Since `_task` and `_state` are `PhantomData`, this struct has a size of 0 bytes.
107///
108/// ### Representation
109/// A zero-sized type [`BranchToken`](file:///Users/sac/wasm4pm-compat/src/workflow.rs) holding a `PhantomData<T>` and `PhantomData<S>`.
110/// Its size in memory is 0 bytes.
111///
112/// ### Structure-only
113/// Models compile-time ownership of an abstract execution path. It holds no runtime task references,
114/// performs no execution, and does not schedule workloads.
115///
116/// ### Graduation
117/// In `wasm4pm`, a token represents a dynamic work item tracked by the runtime database. In the compat library,
118/// it enforces compile-time sequencing and typestate safety.
119pub struct BranchToken<T, S: BranchState> {
120    pub _task: PhantomData<T>,
121    pub _state: PhantomData<S>,
122}
123
124impl<T> BranchToken<T, Pending> {
125    /// Progresses the branch from Pending to Running.
126    ///
127    /// # Examples
128    ///
129    /// ```rust
130    /// use wasm4pm_compat::workflow::{BranchToken, Pending, Running};
131    /// use std::marker::PhantomData;
132    ///
133    /// struct MyTask;
134    /// let token: BranchToken<MyTask, Pending> = BranchToken {
135    ///     _task: PhantomData,
136    ///     _state: PhantomData,
137    /// };
138    /// let running_token: BranchToken<MyTask, Running> = token.start();
139    /// ```
140    #[inline(always)]
141    pub fn start(self) -> BranchToken<T, Running> {
142        BranchToken {
143            _task: PhantomData,
144            _state: PhantomData,
145        }
146    }
147}
148
149impl<T> BranchToken<T, Running> {
150    /// Normal successful completion of the branch.
151    ///
152    /// # Examples
153    ///
154    /// ```rust
155    /// use wasm4pm_compat::workflow::{BranchToken, Running, Completed};
156    /// use std::marker::PhantomData;
157    ///
158    /// struct MyTask;
159    /// let token: BranchToken<MyTask, Running> = BranchToken {
160    ///     _task: PhantomData,
161    ///     _state: PhantomData,
162    /// };
163    /// let completed_token: BranchToken<MyTask, Completed> = token.complete();
164    /// ```
165    #[inline(always)]
166    pub fn complete(self) -> BranchToken<T, Completed> {
167        BranchToken {
168            _task: PhantomData,
169            _state: PhantomData,
170        }
171    }
172}
173
174// =============================================================================
175// 3. Parallel Workflow Carrier (AND-Split State)
176// =============================================================================
177
178/// Tracks the status of two concurrent branches (A and B) at compile time.
179///
180/// ### Representation
181/// Struct [`ParallelWorkflow`](file:///Users/sac/wasm4pm-compat/src/workflow.rs) containing `branch_a` and `branch_b` of type `BranchToken<A, SA>` and `BranchToken<B, SB>`
182/// respectively. Since both tokens are zero-sized, `ParallelWorkflow` is also zero-sized (0 bytes).
183///
184/// ### Structure-only
185/// Models an AND-split/concurrency pattern between two branches without using OS threads, async futures,
186/// or mutexes.
187///
188/// ### Graduation
189/// Graduates to `wasm4pm`'s parallel gateways (BPMN AND-split and AND-join, or Petri Net transitions)
190/// which manage dynamic, multi-threaded or distributed scheduling.
191pub struct ParallelWorkflow<A, B, SA: BranchState, SB: BranchState> {
192    pub branch_a: BranchToken<A, SA>,
193    pub branch_b: BranchToken<B, SB>,
194}
195
196impl<A, B> ParallelWorkflow<A, B, Pending, Pending> {
197    /// Initializes a parallel workflow split (AND-Split).
198    ///
199    /// # Examples
200    ///
201    /// ```rust
202    /// use wasm4pm_compat::workflow::{ParallelWorkflow, Pending};
203    ///
204    /// struct TaskA;
205    /// struct TaskB;
206    /// let workflow: ParallelWorkflow<TaskA, TaskB, Pending, Pending> = ParallelWorkflow::split();
207    /// ```
208    #[inline(always)]
209    pub fn split() -> Self {
210        ParallelWorkflow {
211            branch_a: BranchToken {
212                _task: PhantomData,
213                _state: PhantomData,
214            },
215            branch_b: BranchToken {
216                _task: PhantomData,
217                _state: PhantomData,
218            },
219        }
220    }
221}
222
223// =============================================================================
224// 4. State Transitions (Normal & Cancellation Paths)
225// =============================================================================
226
227impl<A, B, SB: BranchState> ParallelWorkflow<A, B, Running, SB> {
228    /// Completes the task on Branch A.
229    ///
230    /// # Examples
231    ///
232    /// ```rust
233    /// use wasm4pm_compat::workflow::{ParallelWorkflow, Pending, Running, Completed};
234    ///
235    /// struct TaskA;
236    /// struct TaskB;
237    /// let workflow: ParallelWorkflow<TaskA, TaskB, Pending, Pending> = ParallelWorkflow::split();
238    /// // Start both branches
239    /// let workflow = ParallelWorkflow {
240    ///     branch_a: workflow.branch_a.start(),
241    ///     branch_b: workflow.branch_b.start(),
242    /// };
243    /// // Complete branch A
244    /// let workflow: ParallelWorkflow<TaskA, TaskB, Completed, Running> = workflow.complete_a();
245    /// ```
246    #[inline(always)]
247    pub fn complete_a(self) -> ParallelWorkflow<A, B, Completed, SB> {
248        ParallelWorkflow {
249            branch_a: self.branch_a.complete(),
250            branch_b: self.branch_b,
251        }
252    }
253}
254
255impl<A, B, SA: BranchState> ParallelWorkflow<A, B, SA, Running> {
256    /// Completes the task on Branch B.
257    ///
258    /// # Examples
259    ///
260    /// ```rust
261    /// use wasm4pm_compat::workflow::{ParallelWorkflow, Pending, Running, Completed};
262    ///
263    /// struct TaskA;
264    /// struct TaskB;
265    /// let workflow: ParallelWorkflow<TaskA, TaskB, Pending, Pending> = ParallelWorkflow::split();
266    /// // Start both branches
267    /// let workflow = ParallelWorkflow {
268    ///     branch_a: workflow.branch_a.start(),
269    ///     branch_b: workflow.branch_b.start(),
270    /// };
271    /// // Complete branch B
272    /// let workflow: ParallelWorkflow<TaskA, TaskB, Running, Completed> = workflow.complete_b();
273    /// ```
274    #[inline(always)]
275    pub fn complete_b(self) -> ParallelWorkflow<A, B, SA, Completed> {
276        ParallelWorkflow {
277            branch_a: self.branch_a,
278            branch_b: self.branch_b.complete(),
279        }
280    }
281}
282
283impl<A, B> ParallelWorkflow<A, B, Running, Running> {
284    /// Fires a cancellation event from Branch A that targets Branch B.
285    /// This transition consumes the active `BranchToken<B, Running>` and returns
286    /// a `BranchToken<B, Canceled>` token. Because the running token is consumed
287    /// and cannot be cloned, Branch B can never be completed.
288    ///
289    /// # Examples
290    ///
291    /// ```rust
292    /// use wasm4pm_compat::workflow::{ParallelWorkflow, Pending, Running, Completed, Canceled};
293    ///
294    /// struct TaskA;
295    /// struct TaskB;
296    /// let workflow: ParallelWorkflow<TaskA, TaskB, Pending, Pending> = ParallelWorkflow::split();
297    /// // Start both branches
298    /// let workflow = ParallelWorkflow {
299    ///     branch_a: workflow.branch_a.start(),
300    ///     branch_b: workflow.branch_b.start(),
301    /// };
302    /// // Cancel Branch B from Branch A
303    /// let workflow: ParallelWorkflow<TaskA, TaskB, Completed, Canceled> = workflow.cancel_b_from_a();
304    /// ```
305    #[inline(always)]
306    pub fn cancel_b_from_a(self) -> ParallelWorkflow<A, B, Completed, Canceled> {
307        ParallelWorkflow {
308            branch_a: BranchToken {
309                _task: PhantomData,
310                _state: PhantomData,
311            },
312            branch_b: BranchToken {
313                _task: PhantomData,
314                _state: PhantomData,
315            },
316        }
317    }
318}
319
320// =============================================================================
321// 5. Final Synchronization Point (AND-Join)
322// =============================================================================
323
324/// Represents a fully joined or synchronized workflow.
325///
326/// ### Representation
327/// Struct [`CompletedWorkflow`](file:///Users/sac/wasm4pm-compat/src/workflow.rs) containing a single private field: `_private: ()`. It is zero-sized and takes 0 bytes.
328///
329/// ### Structure-only
330/// Serves as a terminal state indicating a workflow has successfully synchronized or terminated. It contains no
331/// executable code, control flow logic, or data payloads.
332///
333/// ### Graduation
334/// In the `wasm4pm` execution engine, a completed workflow corresponds to a closed process instance or a finished case.
335/// Here, it is just a terminal type proving synchronization.
336pub struct CompletedWorkflow {
337    pub _private: (),
338}
339
340/// A synchronization point (AND-Join) namespace for combining concurrent branches.
341///
342/// ### Representation
343/// A zero-sized namespace struct [`JoinPoint`](file:///Users/sac/wasm4pm-compat/src/workflow.rs) that takes 0-bytes of memory.
344///
345/// ### Structure-only
346/// Provides static helper methods to join concurrent branches without runtime synchronization mechanisms
347/// like locks, semaphores, or condition variables.
348///
349/// ### Graduation
350/// In the `wasm4pm` engine, synchronization is managed by a database-backed coordinator or actor system
351/// evaluating event streams. Here, it is purely a type check.
352pub struct JoinPoint;
353
354impl JoinPoint {
355    /// Synchronizes the workflow when both branches complete successfully.
356    ///
357    /// # Examples
358    ///
359    /// ```rust
360    /// use wasm4pm_compat::workflow::{ParallelWorkflow, Pending, Completed, CompletedWorkflow, JoinPoint};
361    ///
362    /// struct TaskA;
363    /// struct TaskB;
364    /// let workflow: ParallelWorkflow<TaskA, TaskB, Pending, Pending> = ParallelWorkflow::split();
365    /// // Start and complete both branches
366    /// let workflow = ParallelWorkflow {
367    ///     branch_a: workflow.branch_a.start().complete(),
368    ///     branch_b: workflow.branch_b.start().complete(),
369    /// };
370    /// // Synchronize using JoinPoint
371    /// let completed: CompletedWorkflow = JoinPoint::join_success(workflow);
372    /// ```
373    #[inline(always)]
374    pub fn join_success<A, B>(
375        _wf: ParallelWorkflow<A, B, Completed, Completed>,
376    ) -> CompletedWorkflow {
377        CompletedWorkflow { _private: () }
378    }
379
380    /// Synchronizes the workflow when Branch B was cancelled.
381    ///
382    /// # Examples
383    ///
384    /// ```rust
385    /// use wasm4pm_compat::workflow::{ParallelWorkflow, Pending, Completed, Canceled, CompletedWorkflow, JoinPoint};
386    ///
387    /// struct TaskA;
388    /// struct TaskB;
389    /// let workflow: ParallelWorkflow<TaskA, TaskB, Pending, Pending> = ParallelWorkflow::split();
390    /// // Start both, then cancel branch B from branch A
391    /// let workflow = ParallelWorkflow {
392    ///     branch_a: workflow.branch_a.start(),
393    ///     branch_b: workflow.branch_b.start(),
394    /// };
395    /// let workflow: ParallelWorkflow<TaskA, TaskB, Completed, Canceled> = workflow.cancel_b_from_a();
396    /// // Synchronize using JoinPoint
397    /// let completed: CompletedWorkflow = JoinPoint::join_canceled_b(workflow);
398    /// ```
399    #[inline(always)]
400    pub fn join_canceled_b<A, B>(
401        _wf: ParallelWorkflow<A, B, Completed, Canceled>,
402    ) -> CompletedWorkflow {
403        CompletedWorkflow { _private: () }
404    }
405}