summaryrefslogtreecommitdiff
path: root/src/script.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/script.rs')
-rw-r--r--src/script.rs168
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();
+ }
+}