add state_get/state_set builtins for frame-persistent key-value store

This commit is contained in:
Will Anderson
2026-04-28 14:37:19 -05:00
parent 36f4c222d9
commit c62ef343f0
2 changed files with 26 additions and 1 deletions
+24 -1
View File
@@ -2322,7 +2322,9 @@ fn dispatch_builtin(
"Content-Type", content_type
).unwrap();
if let Some(dir) = html_dir {
let asset_path = dir.join(file_name);
// Try src/assets/<file> first, then src/<file> as fallback
let asset_path = dir.join("assets").join(file_name);
let asset_path = if asset_path.exists() { asset_path } else { dir.join(file_name) };
if let Ok(bytes) = std::fs::read(&asset_path) {
let _ = request.respond(
tiny_http::Response::from_data(bytes)
@@ -4551,6 +4553,27 @@ fn dispatch_builtin(
BuiltinResult::Handled
}
// ── Frame-persistent key-value state ────────────────────────────────
// state_set / state_get use GLOBAL_STATE so values survive between frames
// when canvas_run_loop calls the draw function repeatedly.
"state_set" => {
// state_set(key: String, val: String) -> Void
let val = match stack.pop().unwrap_or(Value::Nil) { Value::Str(s) => s, _ => String::new() };
let key = match stack.pop().unwrap_or(Value::Nil) { Value::Str(s) => s, _ => String::new() };
GLOBAL_STATE.with(|gs| gs.borrow_mut().insert(key, val));
stack.push(Value::Nil);
BuiltinResult::Handled
}
"state_get" => {
// state_get(key: String) -> String
let key = match stack.pop().unwrap_or(Value::Nil) { Value::Str(s) => s, _ => String::new() };
let val = GLOBAL_STATE.with(|gs| gs.borrow().get(&key).cloned().unwrap_or_default());
stack.push(Value::Str(val));
BuiltinResult::Handled
}
"canvas_run_loop" => {
// canvas_run_loop(draw_fn: String) -> Void (never returns)
let draw_fn = match stack.pop().unwrap_or(Value::Nil) { Value::Str(s) => s, _ => "draw".into() };
+2
View File
@@ -278,6 +278,8 @@ impl TypeEnv {
env.functions.insert("canvas_events".into(), str_fn(vec![], s.clone()));
env.functions.insert("canvas_swap".into(), str_fn(vec![], Type::Void));
env.functions.insert("canvas_run_loop".into(), str_fn(vec![s.clone()], Type::Void));
env.functions.insert("state_set".into(), str_fn(vec![s.clone(), s.clone()], Type::Void));
env.functions.insert("state_get".into(), str_fn(vec![s.clone()], s.clone()));
// Math
for name in &["math_abs","math_floor","math_ceil","math_round","math_sqrt"] {