summaryrefslogtreecommitdiff
path: root/src/script/wasm.rs
diff options
context:
space:
mode:
authorMica White <botahamec@outlook.com>2026-07-06 13:59:36 -0400
committerMica White <botahamec@outlook.com>2026-07-06 13:59:36 -0400
commite8f85e4a723b772c099a3c03a6cb721c48561e4b (patch)
treea879493f40ba52399c2af05eacdb95b8939b0712 /src/script/wasm.rs
parentbdbd5faeb7be5e5f81c1f4a952c8110df9e9b990 (diff)
Fully support WASM (in some contexts)
Diffstat (limited to 'src/script/wasm.rs')
-rw-r--r--src/script/wasm.rs121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/script/wasm.rs b/src/script/wasm.rs
new file mode 100644
index 0000000..96190f6
--- /dev/null
+++ b/src/script/wasm.rs
@@ -0,0 +1,121 @@
+use std::time::UNIX_EPOCH;
+
+use crossterm::{event::KeyCode, style::ContentStyle};
+use wasmi::{Caller, Engine, Linker};
+
+use crate::{buffer::Cell, script::ScriptContext};
+
+fn add_cell(mut caller: Caller<&mut ScriptContext>, character: u32, location: u32, z: u32) {
+ caller.data_mut().buffer.cells.push(Cell {
+ character: char::from_u32(character).unwrap_or_default(),
+ style: ContentStyle::new(),
+ x: (location >> 16) as u16,
+ y: (location & 0xffff) as u16,
+ z: z as u8,
+ });
+}
+
+fn window_size(caller: Caller<&mut ScriptContext>) -> u32 {
+ let window_size = &caller.data().buffer.window_size;
+ ((window_size.rows as u32) << 16) | (window_size.columns as u32)
+}
+
+fn is_key_pressed_this_frame(caller: Caller<&mut ScriptContext>, key_code: u32) -> u32 {
+ const BACKSPACE: u32 = 1 << 24;
+ const ENTER: u32 = 2 << 24;
+ const LEFT: u32 = 3 << 24;
+ const RIGHT: u32 = 4 << 24;
+ const UP: u32 = 5 << 24;
+ const DOWN: u32 = 6 << 24;
+ const HOME: u32 = 7 << 24;
+ const END: u32 = 8 << 24;
+ const PAGE_UP: u32 = 9 << 24;
+ const PAGE_DOWN: u32 = 10 << 24;
+ const TAB: u32 = 11 << 24;
+ const BACK_TAB: u32 = 12 << 24;
+ const DELETE: u32 = 13 << 24;
+ const INSERT: u32 = 14 << 24;
+ const F: u32 = 15 << 24;
+ const CHAR: u32 = 16 << 24;
+ const ESC: u32 = 17 << 24;
+ let key_code = match key_code {
+ 0 => KeyCode::Null,
+ BACKSPACE => KeyCode::Backspace,
+ ENTER => KeyCode::Enter,
+ LEFT => KeyCode::Left,
+ RIGHT => KeyCode::Right,
+ UP => KeyCode::Up,
+ DOWN => KeyCode::Down,
+ HOME => KeyCode::Home,
+ END => KeyCode::End,
+ PAGE_UP => KeyCode::PageUp,
+ PAGE_DOWN => KeyCode::PageDown,
+ TAB => KeyCode::Tab,
+ BACK_TAB => KeyCode::BackTab,
+ DELETE => KeyCode::Delete,
+ INSERT => KeyCode::Insert,
+ F..CHAR => KeyCode::F((key_code & 0xff) as u8),
+ CHAR..ESC => KeyCode::Char(char::from_u32(key_code & 0xffffff).unwrap_or_default()),
+ ESC => KeyCode::Esc,
+ _ => KeyCode::Null,
+ };
+
+ if caller.data().input.is_key_pressed_this_frame(key_code) {
+ 1
+ } else {
+ 0
+ }
+}
+
+fn exit(mut caller: Caller<&mut ScriptContext>) {
+ let _ = caller.data_mut().buffer.finish();
+ std::process::exit(0);
+}
+
+fn random_u64() -> u64 {
+ getrandom::u64().unwrap_or(4)
+}
+
+fn system_now(caller: Caller<&mut ScriptContext>) -> u64 {
+ caller
+ .data()
+ .time
+ .system_now()
+ .duration_since(UNIX_EPOCH)
+ .unwrap()
+ .as_nanos() as u64
+}
+
+fn monotonic_now(caller: Caller<&mut ScriptContext>) -> u64 {
+ caller.data().time.monotonic_now().as_nanos() as u64
+}
+
+fn delta_time(caller: Caller<&mut ScriptContext>) -> u64 {
+ caller.data().time.delta_time().as_nanos() as u64
+}
+
+pub fn linker<'ctx>(
+ engine: &Engine,
+) -> Result<wasmi::Linker<&'ctx mut ScriptContext<'ctx>>, wasmi::Error> {
+ macro_rules! add_fns {
+ ($linker: expr, [$($func: ident),*]) => {
+ $($linker.func_wrap("tortuise", stringify!($func), $func)?;)*
+ };
+ }
+
+ let mut linker = Linker::new(engine);
+ add_fns!(
+ linker,
+ [
+ add_cell,
+ window_size,
+ is_key_pressed_this_frame,
+ exit,
+ random_u64,
+ system_now,
+ monotonic_now,
+ delta_time
+ ]
+ );
+ Ok(linker)
+}