summaryrefslogtreecommitdiff
path: root/src/script/wasm.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/script/wasm.rs')
-rw-r--r--src/script/wasm.rs361
1 files changed, 221 insertions, 140 deletions
diff --git a/src/script/wasm.rs b/src/script/wasm.rs
index 25632fa..9b9cd91 100644
--- a/src/script/wasm.rs
+++ b/src/script/wasm.rs
@@ -1,41 +1,54 @@
-use core::slice;
use std::time::UNIX_EPOCH;
use crossterm::{
event::KeyCode,
style::{Attribute, Attributes, Color, ContentStyle},
};
-use wasmi::{Caller, Engine, Linker};
+use tinywasm::{FuncContext, HostFunction, Imports, ModuleInstance, Store};
use crate::{buffer::Cell, script::FullScriptContext};
use super::Operation;
-unsafe fn str_from_memory<'a>(
- caller: &'a Caller<FullScriptContext<'_>>,
- offset: u32,
- length: u32,
-) -> &'a str {
- let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
+pub struct WasmModule {
+ pub instance: ModuleInstance,
+}
+
+fn str_from_memory(caller: &FuncContext<'_>, offset: u32, length: u32) -> tinywasm::Result<String> {
+ let memory = caller.memory("memory").unwrap();
+ memory.read_string(caller.store(), offset as usize, length as usize)
+}
+
+fn context_mut<'b>(address: u64) -> &'b mut FullScriptContext<'b> {
unsafe {
- str::from_utf8_unchecked(slice::from_raw_parts(
- memory.data_ptr(caller).byte_add(offset as usize),
- length as usize,
- ))
+ std::ptr::with_exposed_provenance_mut::<FullScriptContext<'b>>(address as usize)
+ .as_mut()
+ .unwrap_unchecked()
+ }
+}
+
+fn context_ref<'b>(address: u64) -> &'b FullScriptContext<'b> {
+ unsafe {
+ std::ptr::with_exposed_provenance::<FullScriptContext<'b>>(address as usize)
+ .as_ref()
+ .unwrap_unchecked()
}
}
-#[allow(clippy::too_many_arguments)]
fn add_cell(
- mut caller: Caller<FullScriptContext<'_>>,
- character: u32,
- location: u32,
- z: u32,
- foreground_color: u32,
- background_color: u32,
- underline_color: u32,
- attributes: u32,
-) {
+ _caller: FuncContext<'_>,
+ (
+ context,
+ character,
+ location,
+ z,
+ foreground_color,
+ background_color,
+ underline_color,
+ attributes,
+ ): (u64, u32, u32, u32, u32, u32, u32, u32),
+) -> tinywasm::Result<()> {
+ puffin::profile_function!();
const STANDARD_COLOR: u32 = 1 << 24;
const ANSI_COLOR: u32 = 2 << 24;
const RGB_COLOR: u32 = 3 << 24;
@@ -127,8 +140,7 @@ fn add_cell(
attribute_set.set(Attribute::OverLined);
}
- caller
- .data_mut()
+ context_mut(context)
.operation_queue
.push(Operation::AddCell(Cell {
character: char::from_u32(character).unwrap_or_default(),
@@ -142,14 +154,20 @@ fn add_cell(
y: (location & 0xffff) as u16,
z: z as u8,
}));
+ Ok(())
}
-fn window_size(caller: Caller<FullScriptContext<'_>>) -> u32 {
- let window_size = &caller.data().buffer.window_size;
- ((window_size.rows as u32) << 16) | (window_size.columns as u32)
+fn window_size(_caller: FuncContext<'_>, context: u64) -> tinywasm::Result<u32> {
+ puffin::profile_function!();
+ let window_size = &context_ref(context).buffer.window_size;
+ Ok(((window_size.rows as u32) << 16) | (window_size.columns as u32))
}
-fn is_key_pressed_this_frame(caller: Caller<FullScriptContext<'_>>, key_code: u32) -> u32 {
+fn is_key_pressed_this_frame(
+ _caller: FuncContext<'_>,
+ (context, key_code): (u64, u32),
+) -> tinywasm::Result<u32> {
+ puffin::profile_function!();
const BACKSPACE: u32 = 1 << 24;
const ENTER: u32 = 2 << 24;
const LEFT: u32 = 3 << 24;
@@ -189,21 +207,24 @@ fn is_key_pressed_this_frame(caller: Caller<FullScriptContext<'_>>, key_code: u3
_ => KeyCode::Null,
};
- if caller.data().input.is_key_pressed_this_frame(key_code) {
- 1
- } else {
- 0
- }
+ Ok(
+ if context_ref(context)
+ .input
+ .is_key_pressed_this_frame(key_code)
+ {
+ 1
+ } else {
+ 0
+ },
+ )
}
-fn log(caller: Caller<FullScriptContext<'_>>, severity: u32, offset: u32, length: u32) {
- let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
- let message = unsafe {
- str::from_utf8_unchecked(slice::from_raw_parts(
- memory.data_ptr(&caller).byte_add(offset as usize),
- length as usize,
- ))
- };
+fn log(
+ caller: FuncContext<'_>,
+ (severity, offset, length): (u32, u32, u32),
+) -> tinywasm::Result<()> {
+ puffin::profile_function!();
+ let message = str_from_memory(&caller, offset, length)?;
let severity = match severity {
1 => log::Level::Error,
2 => log::Level::Warn,
@@ -213,103 +234,129 @@ fn log(caller: Caller<FullScriptContext<'_>>, severity: u32, offset: u32, length
_ => log::Level::Error,
};
log::log!(severity, "{message}");
+ Ok(())
}
-fn exit(mut caller: Caller<FullScriptContext<'_>>) {
- caller.data_mut().operation_queue.push(Operation::Exit)
+fn exit(_caller: FuncContext<'_>, context: u64) -> tinywasm::Result<()> {
+ puffin::profile_function!();
+ context_mut(context).operation_queue.push(Operation::Exit);
+ Ok(())
}
-fn random_u64() -> u64 {
- getrandom::u64().unwrap_or(4)
+fn random_u64(_caller: FuncContext<'_>, (): ()) -> tinywasm::Result<u64> {
+ puffin::profile_function!();
+ Ok(getrandom::u64().unwrap_or(4))
}
-fn scene_id_by_name(caller: Caller<FullScriptContext<'_>>, offset: u32, length: u32) -> u32 {
- let name = unsafe { str_from_memory(&caller, offset, length) };
- crate::scene::scene_id_by_name(&caller.data().manifest.scenes, name)
- .map(|u| u as u32)
- .unwrap_or(u32::MAX)
+fn scene_id_by_name(
+ caller: FuncContext<'_>,
+ (context, offset, length): (u64, u32, u32),
+) -> tinywasm::Result<u32> {
+ puffin::profile_function!();
+ let name = str_from_memory(&caller, offset, length)?;
+ Ok(
+ crate::scene::scene_id_by_name(&context_ref(context).manifest.scenes, &name)
+ .map(|u| u as u32)
+ .unwrap_or(u32::MAX),
+ )
}
-fn preload_scene(mut caller: Caller<FullScriptContext<'_>>, id: u32) {
- caller
- .data_mut()
+fn preload_scene(_caller: FuncContext<'_>, (context, id): (u64, u32)) -> tinywasm::Result<()> {
+ puffin::profile_function!();
+ context_mut(context)
.operation_queue
- .push(Operation::PreloadScene(id as usize))
+ .push(Operation::PreloadScene(id as usize));
+ Ok(())
}
-fn is_scene_loaded(caller: Caller<FullScriptContext<'_>>, id: u32) -> u32 {
- let context = caller.data();
- crate::scene::is_scene_loaded(
+fn is_scene_loaded(_caller: FuncContext<'_>, (context, id): (u64, u32)) -> tinywasm::Result<u32> {
+ puffin::profile_function!();
+ let context = context_ref(context);
+ Ok(crate::scene::is_scene_loaded(
&context.manifest.scenes,
context.scripts,
- context.files,
+ &context.files,
id as usize,
- ) as u32
+ ) as u32)
}
-fn switch_scene(mut caller: Caller<FullScriptContext<'_>>, id: u32) {
- caller
- .data_mut()
+fn switch_scene(_caller: FuncContext<'_>, (context, id): (u64, u32)) -> tinywasm::Result<()> {
+ puffin::profile_function!();
+ context_mut(context)
.operation_queue
.push(Operation::SwitchScene(id as usize));
+ Ok(())
}
-fn script_id_by_name(caller: Caller<FullScriptContext<'_>>, offset: u32, length: u32) -> u32 {
- let context = caller.data();
- let name = unsafe { str_from_memory(&caller, offset, length) };
- context
+fn script_id_by_name(
+ caller: FuncContext<'_>,
+ (context, offset, length): (u64, u32, u32),
+) -> tinywasm::Result<u32> {
+ puffin::profile_function!();
+ let name = str_from_memory(&caller, offset, length)?;
+ let context = context_ref(context);
+ Ok(context
.scripts
- .script_id_by_name(name)
+ .script_id_by_name(&name)
.map(|u| u as u32)
- .unwrap_or(u32::MAX)
+ .unwrap_or(u32::MAX))
}
-fn preload_script(mut caller: Caller<FullScriptContext<'_>>, id: u32) {
- caller
- .data_mut()
+fn preload_script(_caller: FuncContext<'_>, (context, id): (u64, u32)) -> tinywasm::Result<()> {
+ puffin::profile_function!();
+ context_mut(context)
.operation_queue
.push(Operation::PreloadScript(id as usize));
+ Ok(())
}
-fn is_script_loaded(caller: Caller<FullScriptContext<'_>>, id: u32) -> u32 {
- let context = caller.data();
- context.scripts.is_script_loaded(id as usize, context.files) as u32
+fn is_script_loaded(_caller: FuncContext<'_>, (context, id): (u64, u32)) -> tinywasm::Result<u32> {
+ puffin::profile_function!();
+ let context = context_ref(context);
+ Ok(context
+ .scripts
+ .is_script_loaded(id as usize, &context.files) as u32)
}
-fn unload_script(mut caller: Caller<FullScriptContext<'_>>, id: u32) {
- caller
- .data_mut()
+fn unload_script(_caller: FuncContext<'_>, (context, id): (u64, u32)) -> tinywasm::Result<()> {
+ puffin::profile_function!();
+ context_mut(context)
.operation_queue
.push(Operation::UnloadScript(id as usize));
+ Ok(())
}
-fn activate_script(mut caller: Caller<FullScriptContext<'_>>, id: u32) {
- caller
- .data_mut()
+fn activate_script(_caller: FuncContext<'_>, (context, id): (u64, u32)) -> tinywasm::Result<()> {
+ puffin::profile_function!();
+ context_mut(context)
.operation_queue
.push(Operation::ActivateScript(id as usize));
+ Ok(())
}
-fn deactivate_script(mut caller: Caller<FullScriptContext<'_>>, id: u32) {
- caller
- .data_mut()
+fn deactivate_script(_caller: FuncContext<'_>, (context, id): (u64, u32)) -> tinywasm::Result<()> {
+ puffin::profile_function!();
+ context_mut(context)
.operation_queue
.push(Operation::DeactivateScript(id as usize));
+ Ok(())
}
-fn state_size(caller: Caller<FullScriptContext<'_>>) -> u32 {
- let context = caller.data();
- context
+fn state_size(_caller: FuncContext<'_>, context: u64) -> tinywasm::Result<u32> {
+ puffin::profile_function!();
+ let context = context_ref(context);
+ Ok(context
.scripts
.script_states
.get(&context.script_id)
.map(|state| state.len())
- .unwrap_or_default() as u32
+ .unwrap_or_default() as u32)
}
-fn load_state(mut caller: Caller<FullScriptContext<'_>>, offset: u32) {
- let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
- let context = caller.data();
+fn load_state(mut caller: FuncContext<'_>, (context, offset): (u64, u32)) -> tinywasm::Result<()> {
+ puffin::profile_function!();
+ let memory = caller.memory("memory").unwrap();
+ let context = context_ref(context);
let state = context
.scripts
.script_states
@@ -317,119 +364,153 @@ fn load_state(mut caller: Caller<FullScriptContext<'_>>, offset: u32) {
.map(|state| &**state)
.unwrap_or(&[]);
memory.write(&mut caller, offset as usize, state).unwrap();
+ Ok(())
}
-fn save_state(mut caller: Caller<FullScriptContext<'_>>, offset: u32, length: u32) {
+fn save_state(
+ mut caller: FuncContext<'_>,
+ (context, offset, length): (u64, u32, u32),
+) -> tinywasm::Result<()> {
+ puffin::profile_function!();
let offset = offset as usize;
let length = length as usize;
- let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
- let new_state = Box::from(&memory.data(&caller)[offset..(offset + length)]);
- let context = caller.data_mut();
+ let memory = caller.memory("memory").unwrap();
+ let new_state = memory
+ .read_vec(caller.store_mut(), offset, length)
+ .unwrap()
+ .into_boxed_slice();
+ let context = context_mut(context);
context.operation_queue.push(Operation::UpdateState {
script_id: context.script_id,
new_state,
});
+ Ok(())
}
-fn entity_size(caller: Caller<FullScriptContext<'_>>, name: u32, name_len: u32) -> u32 {
- let context = caller.data();
- let name = unsafe { str_from_memory(&caller, name, name_len) };
- context
+fn entity_size(
+ caller: FuncContext<'_>,
+ (context, name, name_len): (u64, u32, u32),
+) -> tinywasm::Result<u32> {
+ puffin::profile_function!();
+ let name = str_from_memory(&caller, name, name_len)?;
+ let context = context_ref(context);
+ Ok(context
.scripts
.entities
- .get(name)
+ .get(&*name)
.map(|entity| entity.len())
- .unwrap_or_default() as u32
+ .unwrap_or_default() as u32)
}
-fn load_entity(mut caller: Caller<FullScriptContext<'_>>, name: u32, name_len: u32, offset: u32) {
- let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
- let name = unsafe { str_from_memory(&caller, name, name_len) };
- let context = caller.data();
+fn load_entity(
+ mut caller: FuncContext<'_>,
+ (context, name, name_len, offset): (u64, u32, u32, u32),
+) -> tinywasm::Result<()> {
+ puffin::profile_function!();
+ let name = str_from_memory(&caller, name, name_len)?;
+ let memory = caller.memory("memory").unwrap();
+ let context = context_ref(context);
let entity = context
.scripts
.entities
- .get(name)
+ .get(&*name)
.map(|entity| &**entity)
.unwrap_or(&[]);
memory.write(&mut caller, offset as usize, entity).unwrap();
+ Ok(())
}
fn save_entity(
- mut caller: Caller<FullScriptContext<'_>>,
- name: u32,
- name_len: u32,
- offset: u32,
- length: u32,
-) {
+ mut caller: FuncContext<'_>,
+ (context, name, name_len, offset, length): (u64, u32, u32, u32, u32),
+) -> tinywasm::Result<()> {
+ puffin::profile_function!();
let offset = offset as usize;
let length = length as usize;
- let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
- let new_state = Box::from(&memory.data(&caller)[offset..(offset + length)]);
- let name = Box::from(unsafe { str_from_memory(&caller, name, name_len) });
- let context = caller.data_mut();
+ let memory = caller.memory("memory").unwrap();
+ let new_state = memory
+ .read_vec(caller.store_mut(), offset, length)
+ .unwrap()
+ .into_boxed_slice();
+ let name = str_from_memory(&caller, name, name_len)?.into_boxed_str();
+ let context = context_mut(context);
context
.operation_queue
.push(Operation::UpdateEntity { name, new_state });
+ Ok(())
}
-fn storage_size(caller: Caller<FullScriptContext<'_>>) -> u32 {
- caller
- .data()
+fn storage_size(_caller: FuncContext<'_>, context: u64) -> tinywasm::Result<u32> {
+ puffin::profile_function!();
+ Ok(context_ref(context)
.storage
.get()
.map(|data| data.len())
- .unwrap_or_default() as u32
+ .unwrap_or_default() as u32)
}
-fn load_storage(mut caller: Caller<FullScriptContext<'_>>, offset: u32) {
- let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
- let context = caller.data();
+fn load_storage(
+ mut caller: FuncContext<'_>,
+ (context, offset): (u64, u32),
+) -> tinywasm::Result<()> {
+ puffin::profile_function!();
+ let memory = caller.memory("memory").unwrap();
+ let context = context_ref(context);
let state = context.storage.get().unwrap_or(&[]);
memory.write(&mut caller, offset as usize, state).unwrap();
+ Ok(())
}
-fn save_storage(mut caller: Caller<FullScriptContext<'_>>, offset: u32, length: u32) {
+fn save_storage(
+ mut caller: FuncContext<'_>,
+ (context, offset, length): (u64, u32, u32),
+) -> tinywasm::Result<()> {
+ puffin::profile_function!();
let offset = offset as usize;
let length = length as usize;
- let memory = caller.get_export("memory").unwrap().into_memory().unwrap();
- let new_save = Box::from(&memory.data(&caller)[offset..(offset + length)]);
- let context = caller.data_mut();
+ let memory = caller.memory("memory").unwrap();
+ let new_save = memory
+ .read_vec(caller.store_mut(), offset, length)
+ .unwrap()
+ .into_boxed_slice();
+ let context = context_mut(context);
context
.operation_queue
.push(Operation::UpdateStorage { new_save });
+ Ok(())
}
-fn system_now(caller: Caller<FullScriptContext<'_>>) -> u64 {
- caller
- .data()
+fn system_now(_caller: FuncContext<'_>, context: u64) -> tinywasm::Result<u64> {
+ puffin::profile_function!();
+ Ok(context_ref(context)
.time
.system_now()
.duration_since(UNIX_EPOCH)
.unwrap()
- .as_nanos() as u64
+ .as_nanos() as u64)
}
-fn monotonic_now(caller: Caller<FullScriptContext<'_>>) -> u64 {
- caller.data().time.monotonic_now().as_nanos() as u64
+fn monotonic_now(_caller: FuncContext<'_>, context: u64) -> tinywasm::Result<u64> {
+ puffin::profile_function!();
+ Ok(context_ref(context).time.monotonic_now().as_nanos() as u64)
}
-fn delta_time(caller: Caller<FullScriptContext<'_>>) -> u64 {
- caller.data().time.delta_time().as_nanos() as u64
+fn delta_time(_caller: FuncContext<'_>, context: u64) -> tinywasm::Result<u64> {
+ puffin::profile_function!();
+ Ok(context_ref(context).time.delta_time().as_nanos() as u64)
}
-pub fn linker<'ctx>(
- engine: &Engine,
-) -> Result<wasmi::Linker<FullScriptContext<'ctx>>, wasmi::Error> {
+pub fn linker(store: &mut Store) -> Result<Imports, tinywasm::Error> {
macro_rules! add_fns {
- ($linker: expr, [$($func: ident),*]) => {
- $($linker.func_wrap("tortuise", stringify!($func), $func)?;)*
+ ($linker: expr, $store: expr, [$($func: ident),*]) => {
+ $($linker.define("tortuise", stringify!($func), HostFunction::from($store, $func));)*
};
}
- let mut linker = Linker::new(engine);
+ let mut linker = Imports::new();
add_fns!(
linker,
+ store,
[
add_cell,
window_size,