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}