All pastes #72Qe5sQSGf Raw Edit

Hew v0.5 — redis-style KV server (Session machine + Store actor, MULTI/EXEC)

public hew v1 · immutable
#72Qe5sQSGf ·published 2026-06-03 01:53 UTC ·by slepp
rendered paste body
// 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");}