TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Statum: Zero-Boilerplate Compile-Time State Machines in Rust

23 pointsby eboody4 months ago

2 comments

bfrog4 months ago
One of the issue with type states if you aren’t aware is the state of each type needs to then be a type parameter of the parent type. Meaning creating a dynamic number of these state machines would be frustrating.<p>Do you have some thoughts or samples of say a Vec of Lights as an extension of the sample tou have?
评论 #42705856 未加载
eboody4 months ago
Hey Rustaceans! I&#x27;ve created a library called *Statum* for building type-safe state machines in Rust. It ensures invalid state transitions are caught at *compile time*, giving you extra safety with minimal boilerplate.<p>---<p>## Quick Example (Minimal)<p>```rust use statum::{state, machine};<p>#[state] pub enum TaskState { New, InProgress, Complete, }<p>#[machine] struct Task&lt;S: TaskState&gt; { id: String, name: String, }<p>impl Task&lt;New&gt; { fn start(self) -&gt; Task&lt;InProgress&gt; { self.transition() } }<p>impl Task&lt;InProgress&gt; { fn complete(self) -&gt; Task&lt;Complete&gt; { self.transition() } }<p>fn main() { let task = Task::new(&quot;task-1&quot;.to_owned(), &quot;Important Task&quot;.to_owned()) .start() .complete(); } ```<p>### How it works - *`#[state]`* transforms your enum variants into separate structs while generating a trait to represent the states. - *`#[machine]`* injects some extra fields to track which state your machine is in, at the type level.<p>---<p>## States with Data<p>Need states to carry extra information?<p>```rust #[state] pub enum DocumentState { Draft, Review(ReviewData), &#x2F;&#x2F; State with associated data Published, }<p>struct ReviewData { reviewer: String, comments: Vec&lt;String&gt;, }<p>impl Document&lt;Draft&gt; { fn submit_for_review(self, reviewer: String) -&gt; Document&lt;Review&gt; { &#x2F;&#x2F; Transition to `Review` with data: self.transition_with(ReviewData { reviewer, comments: vec![], }) } } ```<p>### Accessing State Data<p>When your state has associated data, use `.get_state_data()` or `.get_state_data_mut()`:<p>```rust impl Document&lt;Review&gt; { fn add_comment(&amp;mut self, comment: String) { if let Some(review_data) = self.get_state_data_mut() { review_data.comments.push(comment); } }<p><pre><code> fn get_reviewer(&amp;self) -&gt; Option&lt;&amp;str&gt; { self.get_state_data().map(|data| data.reviewer.as_str()) } fn approve(self) -&gt; Document&lt;Published&gt; { self.transition() }</code></pre> } ```<p>---<p>## Why Statum?<p>Many Rust state machine libraries need: - Complex trait impls - Manual checks for transitions - Runtime guards for state data<p>*Statum* does all of this at compile time with a straightforward API.<p>---<p>## Gotchas: Attribute Ordering - *`#[machine]`* must come before any user `#[derive(...)]` on the same struct, or you may see: ``` error[E0063]: missing fields `marker` and `state_data` ``` This is because the derive macros expand before Statum can inject its hidden fields.<p>---<p>## Feedback Welcome!<p>I&#x27;m actively developing Statum and would love community input: - Which patterns do you commonly use for state machines? - Features you’d like to see added? - Ideas to make the API smoother?<p>---<p>## Installation<p>```bash cargo add statum ```<p>Check it out on [GitHub](<a href="https:&#x2F;&#x2F;github.com&#x2F;eboody&#x2F;statum">https:&#x2F;&#x2F;github.com&#x2F;eboody&#x2F;statum</a>) or [Crates.io](<a href="https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;statum" rel="nofollow">https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;statum</a>). Let me know what you think!