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