engate-attach — typed attach lifecycle.
See engate-types for the philosophy + phase markers. This crate
provides the runtime machinery: Producer / Consumer traits,
the typestate-enforced Attach<P> value, the AttachBuilder, and
the linear-ish History<S> handle.
Quick example
use engate_attach::{Attach, Producer, Consumer};
let attach = Attach::builder()
.producer(my_producer)
.consumer(my_consumer)
.build() // -> Attach<Spawned>
.subscribe()? // -> Attach<Subscribed>, also returns History<S>
.replay(history)? // -> Attach<Synced>
.start_live(); // -> Attach<Live>
// Only an Attach<Live> can render.
attach.run();
Why typestate over runtime FSM
A Result return + match on phase string would also work, but the
compiler would let you write attach.replay() on a Subscribed
that you forgot to subscribe() first. Typestate makes the
malformed call a compile error: Spawned has no replay method;
Subscribed has no start_live method. You CAN'T write the bug.