{"id":"6L33vWtDjC","url":"https://pastebin.ca/6L33vWtDjC","raw_url":"https://raw.anybin.ca/6L33vWtDjC","visibility":"public","access":"public","created_at":1780450455905,"expires_at":null,"fetch_limit":null,"fetches_used":0,"reads_remaining":null,"size_bytes":4741,"syntax_hint":"hew","title":"Hew v0.5 — redis-like server v2 (match dispatch, MULTI/EXEC transactions, conn state machine)","filename":"redis_server.hew","change_note":null,"cipher":null,"cipher_meta":null,"parent_id":null,"root_id":"6L33vWtDjC","version":1,"owner_id":"06F6D6Y710X9HQV90HF93KWQT8","recipient_id":null,"body":"// A redis-like server in Hew v0.5 — command parsing, key/value storage, and\n// MULTI/EXEC transactions, behind actor message-passing.\n//\n// WHAT IS REAL HERE:\n//   * line-oriented command parsing (split + dispatch on the verb via `match`)\n//   * a stateful connection protocol: a Ready/Queuing state machine that queues\n//     commands issued inside MULTI and REPLAYS them on EXEC (or drops on DISCARD)\n//   * HashMap-backed storage, all serialized through the actor mailbox\n//   Commands: PING SET GET DEL EXISTS DBSIZE MULTI EXEC DISCARD\n//\n// WHAT IS NOT HERE YET — the actual TCP listen/accept/stream-read/frame/write\n// loop. On trunk that is blocked by three substrate gaps the v0.5 gauntlet\n// confirmed:\n//   * std::net is un-importable (std::fs tag-aware-drop / D10 codegen gap)\n//   * the active-mode conn.attach surface has a reactor use-after-free (fix in flight)\n//   * Vec<LocalPid<RedisConn>> (to hold one connection actor per client) hits the\n//     Vec-of-actor-handle layout ABI gap\n// So the socket is stood in for by feeding the parser a scripted client session.\n// Swapping that for a real connection is the remaining work, not the logic below.\nenum ConnState {\n    Ready;\n    Queuing;\n}\n\n// Apply one data command against the store; returns a RESP-style reply.\n// Shared by the immediate path and the EXEC replay loop.\nfn run_cmd(store: HashMap<string, string>, line: string) -> string {\n    let parts = line.split(\" \");\n    let verb = parts.get(0);\n    match verb {\n        \"PING\" => \"+PONG\",\n        \"DBSIZE\" => f\":{store.len()}\",\n        \"SET\" => {\n            store.insert(parts.get(1), parts.get(2));\n            \"+OK\"\n        },\n        \"GET\" => match store.get(parts.get(1)) {\n            Some(v) => f\"+{v}\",\n            None => \"-NOT_FOUND\",\n        },\n        \"DEL\" => {\n            let key = parts.get(1);\n            if store.contains_key(key) {\n                store.remove(key);\n                \"+OK\"\n            } else {\n                \"-NOT_FOUND\"\n            }\n        },\n        \"EXISTS\" => if store.contains_key(parts.get(1)) {\n            \":1\"\n        } else {\n            \":0\"\n        },\n        _ => \"-ERR unknown command\",\n    }\n}\n\nactor RedisConn {\n    let data: HashMap<string, string>;\n    let state: ConnState;\n    let queue: Vec<string>;\n    receive fn feed(line: string) -> string {\n        let cmd = line.trim();\n        let verb = cmd.split(\" \").get(0);\n        match verb {\n            \"MULTI\" => match state {\n                ConnState::Ready => {\n                    state = ConnState::Queuing;\n                    \"+OK\"\n                },\n                ConnState::Queuing => \"-ERR MULTI calls can not be nested\",\n            },\n            \"DISCARD\" => match state {\n                ConnState::Queuing => {\n                    state = ConnState::Ready;\n                    queue = Vec::new();\n                    \"+OK\"\n                },\n                ConnState::Ready => \"-ERR DISCARD without MULTI\",\n            },\n            \"EXEC\" => match state {\n                ConnState::Ready => \"-ERR EXEC without MULTI\",\n                ConnState::Queuing => {\n                    state = ConnState::Ready;\n                    var applied = 0;\n                    for i in 0 .. queue.len() {\n                        let _ = run_cmd(data, queue.get(i));\n                        applied = applied + 1;\n                    }\n                    queue = Vec::new();\n                    f\"+EXEC applied {applied} queued command(s)\"\n                },\n            },\n            _ => match state {\n                ConnState::Queuing => {\n                    queue.push(cmd);\n                    \"+QUEUED\"\n                },\n                ConnState::Ready => run_cmd(data, cmd),\n            },\n        }\n    }\n}\n\nfn step(conn: LocalPid<RedisConn>, line: string) {\n    let reply = match await conn.feed(line.clone()) {\n        Ok(r) => r,\n        Err(_) => \"-ASK_FAILED\",\n    };\n    println(f\"{line}  ->  {reply}\");\n}\n\nfn main() {\n    let conn = spawn RedisConn(data: HashMap::new(), state: ConnState::Ready, queue: Vec::new());\n    // A scripted client session — stands in for the not-yet-wired TCP stream.\n    step(conn, \"PING\");\n    step(conn, \"SET greeting hello\");\n    step(conn, \"GET greeting\");\n    step(conn, \"EXISTS greeting\");\n    step(conn, \"DEL greeting\");\n    step(conn, \"GET greeting\");\n\n    // A transaction: queued under MULTI, applied atomically on EXEC.\n    step(conn, \"MULTI\");\n    step(conn, \"SET a 1\");\n    step(conn, \"SET b 2\");\n    step(conn, \"EXEC\");\n    step(conn, \"DBSIZE\");\n    step(conn, \"GET a\");\n\n    // A discarded transaction leaves no trace.\n    step(conn, \"MULTI\");\n    step(conn, \"SET c 3\");\n    step(conn, \"DISCARD\");\n    step(conn, \"EXISTS c\");\n}\n"}