Hew v0.5 — redis-style KV server (Session machine + Store actor, MULTI/EXEC)
// A redis-style key/value server: a Store actor owns the data, a Session
// machine drives MULTI/EXEC transactions on the client side.
//
// Invariants:
//   * All key/value state lives in the Store actor and is mutated only inside
//     its receive fn, so every command is serialized through one mailbox.
//   * A Session is always in exactly one state. MULTI moves Ready -> Buffering;
//     each command then appends to the buffer; EXEC replays the buffer in order
//     and returns to Ready; DISCARD drops the buffer and returns to Ready.
//   * exec applies exactly one command and returns its RESP-style reply.

machine Session {
    events {
        Begin;
        Enqueue { cmd: string; }
        Commit;
        Abort;
    }

    state Ready;
    state Buffering { pending: Vec<string>; }

    on Begin: Ready => Buffering {
        Buffering { pending: Vec::new() }
    }
    on Enqueue(cmd): Buffering => Buffering reenter {
        self.pending.push(cmd);
        Buffering { pending: self.pending }
    }
    on Commit: Buffering => Ready { Ready }
    on Abort: Buffering => Ready { Ready }

    default { state }
}

actor Store {
    let data: HashMap<string, string>;

    receive fn exec(line: string) -> string {
        let parts = line.trim().split(" ");
        let verb = parts.get(0);
        match verb {
            "PING" => "+PONG",
            "DBSIZE" => f":{data.len()}",
            "SET" => {
                data.insert(parts.get(1), parts.get(2));
                "+OK"
            },
            "GET" => match data.get(parts.get(1)) {
                Some(value) => f"+{value}",
                None => "-NOT_FOUND",
            },
            "DEL" => {
                let key = parts.get(1);
                if data.contains_key(key) {
                    data.remove(key);
                    "+OK"
                } else {
                    "-NOT_FOUND"
                }
            },
            "EXISTS" => if data.contains_key(parts.get(1)) { ":1" } else { ":0" },
            _ => "-ERR unknown command",
        }
    }
}

fn apply(store: LocalPid<Store>, line: string) {
    let reply = match await store.exec(line.clone()) {
        Ok(r) => r,
        Err(_) => "-ERR no reply",
    };
    println(f"{line}  ->  {reply}");
}

fn main() {
    let store = spawn Store(data: HashMap::new());

    apply(store, "PING");
    apply(store, "SET greeting hello");
    apply(store, "GET greeting");
    apply(store, "EXISTS greeting");

    // A transaction: MULTI buffers, EXEC replays the buffer in order.
    var session = Ready;
    session.step(Begin);
    session.step(Enqueue { cmd: "SET a 1" });
    session.step(Enqueue { cmd: "SET b 2" });
    match session {
        Buffering { pending } => {
            for i in 0 .. pending.len() {
                apply(store, pending.get(i));
            }
        },
        Ready => {},
    }
    session.step(Commit);

    apply(store, "DBSIZE");
    apply(store, "GET a");
}