diff options
Diffstat (limited to 'src/script.rs')
| -rw-r--r-- | src/script.rs | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/src/script.rs b/src/script.rs new file mode 100644 index 0000000..dd65106 --- /dev/null +++ b/src/script.rs @@ -0,0 +1,168 @@ +use std::path::Path; + +use rustc_hash::FxHashMap; +use wasmer::{Imports, Instance, Module, Store}; + +use crate::{buffer::Buffer, file::FileManager, input::InputManager}; + +pub struct ScriptManager<'a> { + scripts: &'a [ScriptDeclaration], + pub active_scripts: Vec<usize>, + script_states: FxHashMap<usize, Box<[u8]>>, +} + +pub struct ScriptContext<'a> { + pub buffer: &'a mut Buffer, + pub input: &'a InputManager, +} + +type StaticScriptFunction = Option<fn(&mut ScriptContext, &mut Box<[u8]>)>; + +pub enum ScriptDeclaration { + Static { + start: StaticScriptFunction, + update: StaticScriptFunction, + end: StaticScriptFunction, + }, + Wasm { + path: Box<Path>, + }, +} + +pub struct WasmScript { + pub module: Module, + pub instance: Instance, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Profile { + Debug, + Release, +} + +impl<'a> ScriptContext<'a> { + pub fn exit(&mut self) -> ! { + let _ = self.buffer.finish(); + std::process::exit(0); + } +} + +fn get_script_state(states: &mut FxHashMap<usize, Box<[u8]>>, script_id: usize) -> &mut Box<[u8]> { + states.entry(script_id).or_insert(Box::from([])) +} + +impl<'a> ScriptManager<'a> { + pub fn new(scripts: &'a [ScriptDeclaration]) -> Self { + Self { + scripts, + active_scripts: Vec::new(), + script_states: FxHashMap::default(), + } + } + + pub fn activate_script( + &mut self, + script_id: usize, + context: &mut ScriptContext<'_>, + files: &mut FileManager, + ) { + let Some(script_declaration) = self.scripts.get(script_id) else { + unreachable!("The active script does not exist"); + }; + match script_declaration { + ScriptDeclaration::Static { start, .. } => { + start.map(|s| { + s( + context, + get_script_state(&mut self.script_states, script_id), + ) + }); + } + ScriptDeclaration::Wasm { path } => { + let module = files.load_file(path.clone()).unwrap().unwrap_wasm_module(); + let mut store = wasmi::Store::new(&files.wasm_compiler, context); + let instance = self + .linker + .instantiate_and_start(&mut store, &module) + .unwrap(); + } + } + self.active_scripts.push(script_id); + } + + pub fn deactivate_script(&mut self, script_id: usize, context: &mut ScriptContext<'_>) { + self.active_scripts.retain(|element| { + if *element != script_id { + let Some(script) = self.scripts.get(script_id) else { + unreachable!("The active script does not exist"); + }; + match script { + ScriptDeclaration::Static { end, .. } => { + end.map(|s| { + s( + context, + get_script_state(&mut self.script_states, script_id), + ); + }); + } + ScriptDeclaration::Wasm { .. } => todo!("wasm scripts"), + }; + + true + } else { + false + } + }); + } + + pub fn run_scripts(&mut self, context: &mut ScriptContext<'_>) { + for script_id in &self.active_scripts { + let Some(script) = self.scripts.get(*script_id) else { + unreachable!("The active script does not exist"); + }; + match *script { + ScriptDeclaration::Static { update, .. } => { + if let Some(s) = update { + s( + context, + get_script_state(&mut self.script_states, *script_id), + ) + } + } + ScriptDeclaration::Wasm { .. } => todo!("wasm scripts"), + } + } + } + + pub fn reset_script(&mut self, script_id: usize, context: &mut ScriptContext<'_>) { + let script = &self.scripts[script_id]; + match script { + ScriptDeclaration::Static { start, end, .. } => { + if let Some(s) = start { + s( + context, + get_script_state(&mut self.script_states, script_id), + ) + } + if let Some(s) = end { + s( + context, + get_script_state(&mut self.script_states, script_id), + ) + } + } + ScriptDeclaration::Wasm { .. } => todo!("wasm scripts"), + } + } +} + +impl WasmScript { + fn call_function(&self, name: &str, profile: Profile, store: &mut Store, imports: &Imports) { + let instance = match profile { + Profile::Debug => &Instance::new(store, &self.module, imports).unwrap(), + Profile::Release => &self.instance, + }; + let function = instance.exports.get_function(name).unwrap(); + function.call(store, &[]).unwrap(); + } +} |
