seesaw_core 0.6.0

A deterministic, event-driven coordination layer where machines decide, effects execute, and transactions define authority
Documentation

Seesaw

A Redux-style state machine with TypeId-based multi-event dispatch.

Named after the playground equipment that balances back and forth — representing the back-and-forth nature of state transitions.

Guarantees

  • Serial reduction: Reducers are executed serially under a write lock. No two events are ever reduced concurrently, even when emitted from multiple tasks.
  • Multi-event dispatch: Support for multiple event types via TypeId routing.
  • Effect system: Register handlers that react to events and can emit new events, spawn tracked tasks, and access shared dependencies.
  • Per-event reducers: Register reducers for specific event types.

Example

use seesaw::{Engine, effect, reducer};

#[derive(Clone, Debug, Default)]
struct AppState {
    user_count: i32,
    order_count: i32,
}

// Define multiple event types
struct UserCreated { name: String }
struct OrderPlaced { amount: f64 }

// Create store with per-event reducers
let store = Engine::new(AppState::default())
    .with_reducer(reducer::on::<UserCreated>().run(|state, _event| AppState {
        user_count: state.user_count + 1,
        ..state
    }))
    .with_reducer(reducer::on::<OrderPlaced>().run(|state, _event| AppState {
        order_count: state.order_count + 1,
        ..state
    }))
    .with_effect(effect::on::<UserCreated>().run(|event, ctx| async move {
        println!("User created: {}", event.name);
        Ok(())
    }));

// Activate and emit events
let handle = store.activate();
handle.context.emit(UserCreated { name: "Alice".into() });
handle.context.emit(OrderPlaced { amount: 99.99 });
handle.settled().await?;

assert_eq!(store.state().user_count, 1);
assert_eq!(store.state().order_count, 1);