Crates.io | rustate |
lib.rs | rustate |
version | |
source | src |
created_at | 2025-04-18 16:41:59.730069+00 |
updated_at | 2025-04-28 09:33:08.376528+00 |
description | A Rust library for creating and managing state machines, inspired by XState. |
homepage | |
repository | https://github.com/jun784/rustate |
max_upload_size | |
id | 1639643 |
Cargo.toml error: | TOML parse error at line 18, column 1 | 18 | autolib = false | ^^^^^^^ unknown field `autolib`, expected one of `name`, `version`, `edition`, `authors`, `description`, `readme`, `license`, `repository`, `homepage`, `documentation`, `build`, `resolver`, `links`, `default-run`, `default_dash_run`, `rust-version`, `rust_dash_version`, `rust_version`, `license-file`, `license_dash_file`, `license_file`, `licenseFile`, `license_capital_file`, `forced-target`, `forced_dash_target`, `autobins`, `autotests`, `autoexamples`, `autobenches`, `publish`, `metadata`, `keywords`, `categories`, `exclude`, `include` |
size | 0 |
This crate contains the core RuState state machine library.
RuState provides the following features:
TODO: Implement MBT integration. (Currently not implemented)
(Current approach) RuState primarily supports integrating multiple state machines across different crates using shared memory (Arc<Mutex>
, Arc<RwLock>
), allowing state machines within the same process to communicate via shared context or event forwarding.
Event Forwarding Pattern: State machines communicate by forwarding events to each other
use rustate::{Action, Context, Event, Machine, MachineBuilder, State, Transition};
use std::sync::{Arc, Mutex};
// Define a shared state machine in a common crate
pub struct SharedMachineRef {
machine: Arc<Mutex<Machine>>,
}
impl SharedMachineRef {
pub fn new(machine: Machine) -> Self {
Self {
machine: Arc::new(Mutex::new(machine)),
}
}
pub fn send_event(&self, event: &str) -> rustate::Result<bool> {
let mut machine = self.machine.lock().unwrap();
machine.send(event)
}
}
// In crate A: Create a parent machine that forwards events to child
fn setup_parent_machine(child_machine: SharedMachineRef) -> Machine {
let parent_state = State::new("parent");
// Define action that forwards events to child machine
let forward_to_child = Action::new(
"forwardToChild",
ActionType::Transition,
move |_ctx, evt| {
if evt.event_type == "CHILD_EVENT" {
let _ = child_machine.send_event("HANDLE_EVENT");
}
},
);
MachineBuilder::new("parentMachine")
.state(parent_state)
.initial("parent")
.on_entry("parent", forward_to_child)
.build()
.unwrap()
}
Context-Based Communication Pattern: Share data between machines using Context
use rustate::{Context, Machine, MachineBuilder, State, Transition};
use std::sync::{Arc, RwLock};
// Define shared context type in a common crate
#[derive(Clone, Default)]
pub struct SharedContext {
data: Arc<RwLock<serde_json::Value>>,
}
impl SharedContext {
pub fn new() -> Self {
Self {
data: Arc::new(RwLock::new(serde_json::json!({}))),
}
}
pub fn set<T: serde::Serialize>(&self, key: &str, value: T) -> Result<(), serde_json::Error> {
let mut data = self.data.write().unwrap();
match &mut *data {
serde_json::Value::Object(map) => {
map.insert(key.to_string(), serde_json::to_value(value)?);
Ok(())
}
_ => {
*data = serde_json::json!({ key: value });
Ok(())
}
}
}
pub fn get<T: for<'de> serde::Deserialize<'de>>(&self, key: &str) -> Option<T> {
let data = self.data.read().unwrap();
match &*data {
serde_json::Value::Object(map) => map
.get(key)
.and_then(|val| serde_json::from_value(val.clone()).ok()),
_ => None,
}
}
}
// Use in machine actions across different crates
fn create_machines(shared_context: SharedContext) -> (Machine, Machine) {
// Machine in crate A
let machine_a = MachineBuilder::new("machineA")
// ...setup states and transitions...
.on_entry("someState", move |ctx, _evt| {
// Read shared context data
if let Some(value) = shared_context.get::<String>("status") {
ctx.set("localStatus", value).unwrap();
}
})
.build()
.unwrap();
// Machine in crate B
let machine_b = MachineBuilder::new("machineB")
// ...setup states and transitions...
.on_entry("anotherState", move |_ctx, _evt| {
// Update shared context
shared_context.set("status", "active").unwrap();
})
.build()
.unwrap();
(machine_a, machine_b)
}
Hierarchical Integration Pattern: Define parent-child relationships between machines
use rustate::{Action, Machine, MachineBuilder, State, Transition};
// In a common crate: Define a trait for child machines
trait ChildMachine {
fn handle_parent_event(&mut self, event: &str) -> rustate::Result<bool>;
fn is_in_final_state(&self) -> bool;
}
// In child crate: Implement child machine
struct ConcreteChildMachine {
machine: Machine,
}
impl ConcreteChildMachine {
fn new() -> Self {
let final_state = State::new_final("final");
let initial = State::new("initial");
let machine = MachineBuilder::new("childMachine")
.state(initial)
.state(final_state)
.initial("initial")
.transition(Transition::new("initial", "COMPLETE", "final"))
.build()
.unwrap();
Self { machine }
}
}
impl ChildMachine for ConcreteChildMachine {
fn handle_parent_event(&mut self, event: &str) -> rustate::Result<bool> {
self.machine.send(event)
}
fn is_in_final_state(&self) -> bool {
self.machine.is_in("final")
}
}
// In parent crate: Create parent machine that coordinates with child
fn setup_parent_machine(mut child: impl ChildMachine + 'static) -> Machine {
let check_child_status = Action::new(
"checkChildStatus",
ActionType::Transition,
move |ctx, _evt| {
if child.is_in_final_state() {
let _ = ctx.set("childComplete", true);
}
},
);
MachineBuilder::new("parentMachine")
// ...setup states and transitions...
.on_entry("monitoring", check_child_status)
.build()
.unwrap()
}
This approach allows you to build complex applications with modular, type-safe state management across multiple crates, perfect for large Rust applications with distinct domains.
rustate_core
.(Current status as of v0.3.0)
rustate
(e.g., ask pattern, supervision). (Status: Basic implementation exists, enhancements planned).ssot
Integration: Define and potentially implement a workflow for using .ssot
files to define/generate rustate
machines. (Status: Planned)create_machine
macro (potentially in a separate rustate-macros
crate). (Status: Basic macro exists but needs separate crate and testing)