gen_statem: GenStatem* type prefix + cleanup

- rename StatemRef/StatemCallError/StatemSendError -> GenStatem*
- move the inline unit test out of src; consolidate the Switch coverage
  onto a single macro-driven harness in tests/gen_statem.rs
- drop the redundant hand-written Switch test machine and the two
  untracked rejected-direction probes (succ_enums, typed_edges)
- rename examples statem_{fused,macro}.rs -> gen_statem_{fused,macro}.rs
- strip RFC/chunk/spike provenance and fix the mislabeled "throwaway"
  example header and dead cross-references
This commit is contained in:
smarm-agent
2026-06-20 10:48:33 +00:00
parent 3e316066c3
commit 0cf6b80396
6 changed files with 177 additions and 288 deletions
@@ -1,11 +1,9 @@
//! SPIKE (throwaway) — RFC 017 "fused" approach.
//! The hand-written **expansion target** of the `gen_statem!` macro: the same
//! machine as `examples/gen_statem_macro.rs`, written out in full so the
//! primitives can be judged standing on their own. The macro generates exactly
//! this shape; nothing here needs the macro to be correct or safe.
//!
//! This is the hand-written *expansion target* of the eventual `statem!` macro,
//! written out in full so the primitives can be judged standing on their own.
//! A macro would generate exactly this from a `transitions { … }` block; nothing
//! here needs the macro to be correct or safe.
//!
//! The design, as settled over the prior iterations:
//! The design:
//!
//! * States and events are real enums. An invalid state is unrepresentable;
//! there are no bitflags, no `u32` superpositions, no unsafe unions.
@@ -27,18 +25,18 @@
//! wired in is dead code — and dead_code is denied below, making an orphan
//! handler a compile error.
//!
//! * Drops onto the committed `Machine` / `Resolution` / `Cx` primitives with
//! no change to `src/statem.rs`.
//! * Drops onto the `Machine` / `Resolution` / `Cx` primitives with no change
//! to `src/gen_statem.rs`.
//!
//! Default build is clean and runs. A BREAK-CASE MENU at the bottom documents
//! how to make each of the four guarantees fire.
//!
//! Run: `cargo run --example statem_fused`
//! Run: `cargo run --example gen_statem_fused`
#![deny(dead_code, unreachable_patterns)]
use smarm::run;
use smarm::gen_statem::{spawn, Cx, Machine, Reply, Resolution, StatemRef};
use smarm::gen_statem::{spawn, Cx, Machine, Reply, Resolution, GenStatemRef};
// === user types ============================================================
@@ -114,7 +112,7 @@ struct DoorSm {
}
impl DoorSm {
fn start(init: Door) -> StatemRef<DoorSm> {
fn start(init: Door) -> GenStatemRef<DoorSm> {
spawn(DoorSm {
state: init,
data: Data { enters: 0, pushes: 0 },
@@ -184,7 +182,7 @@ impl Machine for DoorSm {
self.state = s; // sole writer of the state cell
self.enter(cx);
}
Resolution::Postpone => unreachable!("postpone lands in chunk 3"),
Resolution::Postpone => unreachable!("postpone is not generated yet"),
Resolution::Unhandled => cx.on_unhandled(),
}
}
@@ -1,18 +1,18 @@
//! RFC 017 — the **same** machine as `examples/statem_fused.rs`, written through
//! the `gen_statem!` macro. Diff this file against that one to see exactly what
//! the macro buys: every `// ===` section there that was boilerplate (the `Ev`
//! The **same** machine as `examples/gen_statem_fused.rs`, written through the
//! `gen_statem!` macro. Diff this file against that one to see exactly what the
//! macro buys: every `// ===` section there that was boilerplate (the `Ev`
//! enum, the `DoorSm` struct, `start`, the whole `Machine` impl, the `enter`
//! dispatch, the stay/transition apply-tail) collapses into the invocation
//! below. What stays hand-written is what carries meaning: the four types, the
//! per-state successor enum, and the handler fns.
//!
//! The point of the exercise is that the macro is *pure sugar*: the four
//! compile-time guarantees the fused spike demonstrates are properties of the
//! emitted code, not of the macro, so they survive expansion unchanged. The
//! compile-time guarantees the hand-written form demonstrates are properties of
//! the emitted code, not of the macro, so they survive expansion unchanged. The
//! BREAK-CASE MENU at the bottom is the same four cases, re-expressed against
//! the macro surface — flip any one on and the compiler fires identically.
//!
//! Run: `cargo run --example statem_macro`
//! Run: `cargo run --example gen_statem_macro`
#![deny(dead_code)] // guarantee #3 (orphan handlers); the macro denies the
// dispatch's own unreachable_patterns internally.
@@ -21,7 +21,7 @@ use smarm::gen_statem;
use smarm::run;
use smarm::gen_statem::Reply;
// === user types (identical to statem_fused.rs) =============================
// === user types (identical to gen_statem_fused.rs) =========================
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum Door {
@@ -91,7 +91,7 @@ gen_statem! {
// You name the bindings the bodies use; the macro can't lend you its own
// `self`/`cx` across macro hygiene. `data` = &mut Data, `prev` = current
// state tag, `cx` = context handle (unused in chunk 1).
// state tag, `cx` = context handle (unused here).
context(data, prev, cx);
enter {
@@ -145,7 +145,7 @@ fn main() {
// ===========================================================================
// BREAK-CASE MENU — the four guarantees, through the macro. Each fires exactly
// as it does in the hand-written statem_fused.rs.
// as it does in the hand-written gen_statem_fused.rs.
//
// 1. ORPHAN HANDLER (dead_code -> error):
// add `fn on_slam(_d: &mut Data) {}` and don't reference it.
@@ -157,8 +157,8 @@ fn main() {
// NOTE: this example is a separate crate from `smarm`, so rustc's
// in_external_macro rule SILENCES this lint here even though the macro
// denies it — the duplicate compiles. The guarantee is real only for
// machines defined inside the smarm crate (see the unit test in
// src/statem.rs). This is the documented macro_rules! limitation.
// machines defined inside the `smarm` crate itself. This is the documented
// macro_rules! limitation.
//
// 3. MISSING PAIR (non-exhaustive match, E0004):
// delete the `cast Cast::Push | Cast::Pull | Cast::Lock => unhandled,`