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::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) }