From 7efcec919444ce649437944a78605f9d06c5e940 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Tue, 28 May 2024 01:00:49 -0700 Subject: [PATCH] refactor(wasm): remap wasm interface (rust side) --- Cargo.lock | 1 + ic10emu/src/errors.rs | 6 + ic10emu/src/vm.rs | 172 ++++++++++++++- ic10emu_wasm/Cargo.toml | 35 ++- ic10emu_wasm/build.rs | 11 +- ic10emu_wasm/src/lib.rs | 475 ++++++++++------------------------------ ic10lsp_wasm/Cargo.toml | 26 +++ 7 files changed, 351 insertions(+), 375 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 360d031..c351575 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -720,6 +720,7 @@ dependencies = [ "serde-wasm-bindgen 0.6.5", "serde_derive", "serde_with", + "stationeers_data", "strum", "thiserror", "tsify", diff --git a/ic10emu/src/errors.rs b/ic10emu/src/errors.rs index aaa3cb2..085680e 100644 --- a/ic10emu/src/errors.rs +++ b/ic10emu/src/errors.rs @@ -46,8 +46,12 @@ pub enum VMError { NotAnItem(ObjectID), #[error("object {0} is not programmable")] NotProgrammable(ObjectID), + #[error("object {0} is not memory writable")] + NotMemoryWritable(ObjectID), #[error("object {0} is not a circuit holder or programmable")] NotCircuitHolderOrProgrammable(ObjectID), + #[error("object {0} is not a circuit holder or memory writable")] + NotCircuitHolderOrMemoryWritable(ObjectID), #[error("object {0} is a circuit holder but there is no programmable ic present")] NoIC(ObjectID), #[error("{0}")] @@ -56,6 +60,8 @@ pub enum VMError { MissingChild(ObjectID), #[error("object {0} is not parentable")] NotParentable(ObjectID), + #[error("object {0} is not logicable")] + NotLogicable(ObjectID), } #[derive(Error, Debug, Serialize, Deserialize)] diff --git a/ic10emu/src/vm.rs b/ic10emu/src/vm.rs index e7faa41..9666617 100644 --- a/ic10emu/src/vm.rs +++ b/ic10emu/src/vm.rs @@ -238,7 +238,7 @@ impl VM { } /// Creates a new network adn return it's ID - pub fn add_network(self: &Rc) -> u32 { + pub fn add_network(self: &Rc) -> ObjectID { let next_id = self.network_id_space.borrow_mut().next(); self.networks.borrow_mut().insert( next_id, @@ -257,7 +257,7 @@ impl VM { } /// Get network form Id - pub fn get_network(self: &Rc, id: u32) -> Option { + pub fn get_network(self: &Rc, id: ObjectID) -> Option { self.networks.borrow().get(&id).cloned() } @@ -265,7 +265,11 @@ impl VM { /// /// Iterates over all objects borrowing them mutably, never call unless VM is not currently /// stepping or you'll get reborrow panics - pub fn change_device_id(self: &Rc, old_id: u32, new_id: u32) -> Result<(), VMError> { + pub fn change_device_id( + self: &Rc, + old_id: ObjectID, + new_id: ObjectID, + ) -> Result<(), VMError> { if self.id_space.borrow().has_id(&new_id) { return Err(VMError::IdInUse(new_id)); } @@ -321,7 +325,7 @@ impl VM { /// Set program code if it's valid /// Object Id is the programmable Id or the circuit holder's id - pub fn set_code(self: &Rc, id: u32, code: &str) -> Result { + pub fn set_code(self: &Rc, id: ObjectID, code: &str) -> Result { let obj = self .objects .borrow() @@ -356,7 +360,7 @@ impl VM { /// Set program code and translate invalid lines to Nop, collecting errors /// Object Id is the programmable Id or the circuit holder's id - pub fn set_code_invalid(self: &Rc, id: u32, code: &str) -> Result { + pub fn set_code_invalid(self: &Rc, id: ObjectID, code: &str) -> Result { let obj = self .objects .borrow() @@ -389,6 +393,143 @@ impl VM { Err(VMError::NoIC(id)) } + /// Set register of integrated circuit + /// Object Id is the circuit Id or the circuit holder's id + pub fn set_register( + self: &Rc, + id: ObjectID, + index: u32, + val: f64, + ) -> Result { + let obj = self + .objects + .borrow() + .get(&id) + .cloned() + .ok_or(VMError::UnknownId(id))?; + { + let mut obj_ref = obj.borrow_mut(); + if let Some(circuit) = obj_ref.as_mut_integrated_circuit() { + let last = circuit.set_register(0, index, val)?; + return Ok(last); + } + } + let ic_obj = { + let obj_ref = obj.borrow(); + if let Some(circuit_holder) = obj_ref.as_circuit_holder() { + circuit_holder.get_ic() + } else { + return Err(VMError::NotCircuitHolderOrProgrammable(id)); + } + }; + if let Some(ic_obj) = ic_obj { + let mut ic_obj_ref = ic_obj.borrow_mut(); + if let Some(circuit) = ic_obj_ref.as_mut_integrated_circuit() { + let last = circuit.set_register(0, index, val)?; + return Ok(last); + } + return Err(VMError::NotProgrammable(*ic_obj_ref.get_id())); + } + Err(VMError::NoIC(id)) + } + + /// Set memory at address of object with memory + /// Object Id is the memory writable Id or the circuit holder's id + pub fn set_memory( + self: &Rc, + id: ObjectID, + address: u32, + val: f64, + ) -> Result { + let obj = self + .objects + .borrow() + .get(&id) + .cloned() + .ok_or(VMError::UnknownId(id))?; + { + let mut obj_ref = obj.borrow_mut(); + if let Some(circuit) = obj_ref.as_mut_memory_writable() { + let last = circuit + .get_memory(address as i32) + .map_err(Into::::into)?; + circuit + .set_memory(address as i32, val) + .map_err(Into::::into)?; + return Ok(last); + } + } + let ic_obj = { + let obj_ref = obj.borrow(); + if let Some(circuit_holder) = obj_ref.as_circuit_holder() { + circuit_holder.get_ic() + } else { + None + } + }; + if let Some(ic_obj) = ic_obj { + let mut ic_obj_ref = ic_obj.borrow_mut(); + if let Some(circuit) = ic_obj_ref.as_mut_memory_writable() { + let last = circuit + .get_memory(address as i32) + .map_err(Into::::into)?; + circuit + .set_memory(address as i32, val) + .map_err(Into::::into)?; + return Ok(last); + } + return Err(VMError::NotMemoryWritable(*ic_obj_ref.get_id())); + } + Err(VMError::NotCircuitHolderOrMemoryWritable(id)) + } + + /// Set logic field on a logicable object + pub fn set_logic_field( + self: &Rc, + id: ObjectID, + lt: LogicType, + val: f64, + force: bool, + ) -> Result<(), VMError> { + let obj = self + .objects + .borrow() + .get(&id) + .cloned() + .ok_or(VMError::UnknownId(id))?; + let mut obj_ref = obj.borrow_mut(); + let logicable = obj_ref + .as_mut_logicable() + .ok_or(VMError::NotLogicable(id))?; + logicable + .set_logic(lt, val, force) + .map_err(Into::::into)?; + Ok(()) + } + + /// Set slot logic filed on device object + pub fn set_slot_logic_field( + self: &Rc, + id: ObjectID, + slt: LogicSlotType, + index: u32, + val: f64, + force: bool, + ) -> Result<(), VMError> { + let obj = self + .objects + .borrow() + .get(&id) + .cloned() + .ok_or(VMError::UnknownId(id))?; + let mut obj_ref = obj.borrow_mut(); + let device = obj_ref.as_mut_device().ok_or(VMError::NotLogicable(id))?; + device + .set_slot_logic(slt, index as f64, val, force) + .map_err(Into::::into)?; + Ok(()) + } + /// returns a list of device ids modified in the last operations pub fn last_operation_modified(self: &Rc) -> Vec { self.operation_modified.borrow().clone() @@ -396,7 +537,7 @@ impl VM { pub fn step_programmable( self: &Rc, - id: u32, + id: ObjectID, advance_ip_on_err: bool, ) -> Result<(), VMError> { let obj = self @@ -440,7 +581,7 @@ impl VM { /// returns true if executed 128 lines, false if returned early. pub fn run_programmable( self: &Rc, - id: u32, + id: ObjectID, ignore_errors: bool, ) -> Result { let obj = self @@ -573,7 +714,11 @@ impl VM { } } - pub fn get_network_channel(self: &Rc, id: u32, channel: usize) -> Result { + pub fn get_network_channel( + self: &Rc, + id: ObjectID, + channel: usize, + ) -> Result { let network = self .networks .borrow() @@ -653,7 +798,7 @@ impl VM { pub fn set_pin( self: &Rc, - id: u32, + id: ObjectID, pin: usize, val: Option, ) -> Result { @@ -1071,6 +1216,13 @@ impl VM { Ok(last) } + pub fn freeze_object(self: &Rc, id: ObjectID) -> Result { + let Some(obj) = self.objects.borrow().get(&id).cloned() else { + return Err(VMError::UnknownId(id)); + }; + Ok(FrozenObject::freeze_object(&obj, self)?) + } + pub fn save_vm_state(self: &Rc) -> Result { Ok(FrozenVM { objects: self @@ -1085,7 +1237,7 @@ impl VM { { None } else { - Some(FrozenObject::freeze_object(obj, self)) + Some(FrozenObject::freeze_object_sparse(obj, self)) } }) .collect::, _>>()?, diff --git a/ic10emu_wasm/Cargo.toml b/ic10emu_wasm/Cargo.toml index ea06db8..5a0f233 100644 --- a/ic10emu_wasm/Cargo.toml +++ b/ic10emu_wasm/Cargo.toml @@ -5,8 +5,9 @@ version.workspace = true edition.workspace = true [dependencies] +stationeers_data = { path = "../stationeers_data", features = ["tsify"] } ic10emu = { path = "../ic10emu", features = ["tsify"] } -console_error_panic_hook = {version = "0.1.7", optional = true} +console_error_panic_hook = { version = "0.1.7", optional = true } js-sys = "0.3.69" web-sys = { version = "0.3.69", features = ["WritableStream", "console"] } wasm-bindgen = "0.2.92" @@ -24,12 +25,42 @@ serde_derive = "1.0.203" [build-dependencies] ic10emu = { path = "../ic10emu" } -strum = { version = "0.26.2"} +strum = { version = "0.26.2" } itertools = "0.13.0" [features] default = ["console_error_panic_hook"] console_error_panic_hook = ["dep:console_error_panic_hook"] +prefab_database = [ + "ic10emu/prefab_database", + "stationeers_data/prefab_database", +] [lib] crate-type = ["cdylib", "rlib"] + +[profile.release] +# Tell `rustc` to optimize for small code size. +opt-level = "s" + +[package.metadata.wasm-pack.profile.dev] +wasm-opt = ['-O'] + +[package.metadata.wasm-pack.profile.dev.wasm-bindgen] +# Should we enable wasm-bindgen's debug assertions in its generated JS glue? +debug-js-glue = true +# Should wasm-bindgen demangle the symbols in the "name" custom section? +demangle-name-section = true +# Should we emit the DWARF debug info custom sections? +dwarf-debug-info = false +# Should we omit the default import path? +omit-default-module-path = false + +[package.metadata.wasm-pack.profile.release] +wasm-opt = ['-Os'] + +[package.metadata.wasm-pack.profile.release.wasm-bindgen] +debug-js-glue = false +demangle-name-section = true +dwarf-debug-info = false +omit-default-module-path = false diff --git a/ic10emu_wasm/build.rs b/ic10emu_wasm/build.rs index b83ec9b..ab4a158 100644 --- a/ic10emu_wasm/build.rs +++ b/ic10emu_wasm/build.rs @@ -1,12 +1,7 @@ -use std::{ - env, - fs::{self, File}, - io::{BufWriter, Write}, - path::Path, -}; -use itertools::Itertools; -use strum::IntoEnumIterator; + + + fn main() { // let out_dir = env::var_os("OUT_DIR").unwrap(); diff --git a/ic10emu_wasm/src/lib.rs b/ic10emu_wasm/src/lib.rs index eadff29..8afdf0f 100644 --- a/ic10emu_wasm/src/lib.rs +++ b/ic10emu_wasm/src/lib.rs @@ -3,20 +3,19 @@ mod utils; // mod types; use ic10emu::{ - errors::{TemplateError, VMError}, + errors::VMError, vm::{ object::{templates::FrozenObject, ObjectID, VMObject}, FrozenVM, VM, }, }; -use serde_derive::{Deserialize, Serialize}; -// use types::{Registers, Stack}; - -use std::{cell::RefCell, rc::Rc, str::FromStr}; - use itertools::Itertools; -// use std::iter::FromIterator; -// use itertools::Itertools; +use serde_derive::{Deserialize, Serialize}; + +use stationeers_data::enums::script::{LogicSlotType, LogicType}; + +use std::rc::Rc; + use wasm_bindgen::prelude::*; #[wasm_bindgen] @@ -24,12 +23,6 @@ extern "C" { fn alert(s: &str); } -// #[wasm_bindgen] -// pub struct DeviceRef { -// device: Rc>, -// vm: Rc>, -// } - use thiserror::Error; #[derive(Error, Debug, Serialize, Deserialize)] @@ -40,330 +33,12 @@ pub enum BindingError { OutOfBounds(usize, usize), } -// #[wasm_bindgen] -// impl DeviceRef { -// fn from_device(device: Rc>, vm: Rc>) -> Self { -// DeviceRef { device, vm } -// } -// -// #[wasm_bindgen(getter)] -// pub fn id(&self) -> ObjectID { -// self.device.id -// } -// -// #[wasm_bindgen(getter)] -// pub fn ic(&self) -> Option { -// self.device.ic -// } -// -// #[wasm_bindgen(getter)] -// pub fn name(&self) -> Option { -// self.device.name.clone() -// } -// -// #[wasm_bindgen(getter, js_name = "nameHash")] -// pub fn name_hash(&self) -> Option { -// self.device.name_hash -// } -// -// #[wasm_bindgen(getter, js_name = "prefabName")] -// pub fn prefab_name(&self) -> Option { -// self.device -// -// .prefab -// .as_ref() -// .map(|prefab| prefab.name.clone()) -// } -// -// #[wasm_bindgen(getter, js_name = "prefabHash")] -// pub fn prefab_hash(&self) -> Option { -// self.device -// -// .prefab -// .as_ref() -// .map(|prefab| prefab.hash) -// } -// -// #[wasm_bindgen(getter, skip_typescript)] -// pub fn fields(&self) -> JsValue { -// serde_wasm_bindgen::to_value(&self.device.get_fields(&self.vm.borrow())).unwrap() -// } -// -// #[wasm_bindgen(getter)] -// pub fn slots(&self) -> types::Slots { -// types::Slots::from_iter(self.device.slots.iter()) -// } -// -// #[wasm_bindgen(getter, skip_typescript)] -// pub fn reagents(&self) -> JsValue { -// serde_wasm_bindgen::to_value(&self.device.reagents).unwrap() -// } -// -// #[wasm_bindgen(getter, skip_typescript)] -// pub fn connections(&self) -> JsValue { -// serde_wasm_bindgen::to_value(&self.device.connections).unwrap() -// } -// -// #[wasm_bindgen(getter, js_name = "ip")] -// pub fn ic_ip(&self) -> Option { -// self.device.ic.as_ref().and_then(|ic| { -// self.vm -// -// .circuit_holders -// .get(ic) -// .map(|ic| ic.as_ref().ip()) -// }) -// } -// -// #[wasm_bindgen(getter, js_name = "instructionCount")] -// pub fn ic_instruction_count(&self) -> Option { -// self.device.ic.as_ref().and_then(|ic| { -// self.vm -// -// .circuit_holders -// .get(ic) -// .map(|ic| ic.as_ref().ic.get()) -// }) -// } -// -// #[wasm_bindgen(getter, js_name = "stack")] -// pub fn ic_stack(&self) -> Option { -// self.device.ic.as_ref().and_then(|ic| { -// self.vm -// -// .circuit_holders -// .get(ic) -// .map(|ic| Stack(*ic.as_ref().stack.borrow())) -// }) -// } -// -// #[wasm_bindgen(getter, js_name = "registers")] -// pub fn ic_registers(&self) -> Option { -// self.device.ic.as_ref().and_then(|ic| { -// self.vm -// -// .circuit_holders -// .get(ic) -// .map(|ic| Registers(*ic.as_ref().registers.borrow())) -// }) -// } -// -// #[wasm_bindgen(getter, js_name = "aliases", skip_typescript)] -// pub fn ic_aliases(&self) -> JsValue { -// let aliases = &self.device.ic.as_ref().and_then(|ic| { -// self.vm -// -// .circuit_holders -// .get(ic) -// .map(|ic| ic.as_ref().aliases.borrow().clone()) -// }); -// serde_wasm_bindgen::to_value(aliases).unwrap() -// } -// -// #[wasm_bindgen(getter, js_name = "defines", skip_typescript)] -// pub fn ic_defines(&self) -> JsValue { -// let defines = &self.device.ic.as_ref().and_then(|ic| { -// self.vm -// -// .circuit_holders -// .get(ic) -// .map(|ic| ic.as_ref().defines.borrow().clone()) -// }); -// serde_wasm_bindgen::to_value(defines).unwrap() -// } -// -// #[wasm_bindgen(getter, js_name = "pins", skip_typescript)] -// pub fn ic_pins(&self) -> JsValue { -// let pins = &self.device.ic.as_ref().and_then(|ic| { -// self.vm -// -// .circuit_holders -// .get(ic) -// .map(|ic| *ic.as_ref().pins.borrow()) -// }); -// serde_wasm_bindgen::to_value(pins).unwrap() -// } -// -// #[wasm_bindgen(getter, js_name = "state")] -// pub fn ic_state(&self) -> Option { -// self.device -// -// .ic -// .as_ref() -// .and_then(|ic| { -// self.vm -// -// .circuit_holders -// .get(ic) -// .map(|ic| ic.state.clone()) -// }) -// .map(|state| state.to_string()) -// } -// -// #[wasm_bindgen(getter, js_name = "program", skip_typescript)] -// pub fn ic_program(&self) -> JsValue { -// let prog = &self.device.ic.as_ref().and_then(|ic| { -// self.vm -// -// .circuit_holders -// .get(ic) -// .map(|ic| ic.program.borrow().clone()) -// }); -// serde_wasm_bindgen::to_value(prog).unwrap() -// } -// -// #[wasm_bindgen(getter, js_name = "code")] -// pub fn get_code(&self) -> Option { -// self.device.ic.as_ref().and_then(|ic| { -// self.vm -// -// .circuit_holders -// .get(ic) -// .map(|ic| ic.code.borrow().clone()) -// }) -// } -// -// #[wasm_bindgen(js_name = "step")] -// pub fn step_ic(&self, advance_ip_on_err: bool) -> Result { -// let id = self.device.id; -// Ok(self.vm.step_ic(id, advance_ip_on_err)?) -// } -// -// #[wasm_bindgen(js_name = "run")] -// pub fn run_ic(&self, ignore_errors: bool) -> Result { -// let id = self.device.id; -// Ok(self.vm.run_ic(id, ignore_errors)?) -// } -// -// #[wasm_bindgen(js_name = "reset")] -// pub fn reset_ic(&self) -> Result { -// let id = self.device.id; -// Ok(self.vm.reset_ic(id)?) -// } -// -// #[wasm_bindgen(js_name = "setCode")] -// /// Set program code if it's valid -// pub fn set_code(&self, code: &str) -> Result { -// let id = self.device.id; -// Ok(self.vm.set_code(id, code)?) -// } -// -// #[wasm_bindgen(js_name = "setCodeInvalid")] -// /// Set program code and translate invalid lines to Nop, collecting errors -// pub fn set_code_invlaid(&self, code: &str) -> Result { -// let id = self.device.id; -// Ok(self.vm.set_code_invalid(id, code)?) -// } -// -// #[wasm_bindgen(js_name = "setRegister")] -// pub fn ic_set_register(&self, index: ObjectID, val: f64) -> Result { -// let ic_id = *self -// .device -// -// .ic -// .as_ref() -// .ok_or(VMError::NoIC(self.device.id))?; -// let vm_borrow = self.vm; -// let ic = vm_borrow -// .circuit_holders -// .get(&ic_id) -// .ok_or(VMError::NoIC(self.device.id))?; -// let result = ic.set_register(0, index, val)?; -// Ok(result) -// } -// -// #[wasm_bindgen(js_name = "setStack")] -// pub fn ic_set_stack(&self, address: f64, val: f64) -> Result { -// let ic_id = *self -// .device -// -// .ic -// .as_ref() -// .ok_or(VMError::NoIC(self.device.id))?; -// let vm_borrow = self.vm; -// let ic = vm_borrow -// .circuit_holders -// .get(&ic_id) -// .ok_or(VMError::NoIC(self.device.id))?; -// let result = ic.poke(address, val)?; -// Ok(result) -// } -// -// #[wasm_bindgen(js_name = "setName")] -// pub fn set_name(&self, name: &str) { -// self.device.set_name(name) -// } -// -// #[wasm_bindgen(js_name = "setField", skip_typescript)] -// pub fn set_field(&self, field: &str, value: f64, force: bool) -> Result<(), JsError> { -// let logic_typ = LogicType::from_str(field)?; -// let mut device_ref = self.device; -// device_ref.set_field(logic_typ, value, &self.vm, force)?; -// Ok(()) -// } -// -// #[wasm_bindgen(js_name = "setSlotField", skip_typescript)] -// pub fn set_slot_field( -// &self, -// slot: f64, -// field: &str, -// value: f64, -// force: bool, -// ) -> Result<(), JsError> { -// let logic_typ = LogicSlotType::from_str(field)?; -// let mut device_ref = self.device; -// device_ref.set_slot_field(slot, logic_typ, value, &self.vm, force)?; -// Ok(()) -// } -// -// #[wasm_bindgen(js_name = "getSlotField", skip_typescript)] -// pub fn get_slot_field(&self, slot: f64, field: &str) -> Result { -// let logic_typ = LogicSlotType::from_str(field)?; -// let device_ref = self.device; -// Ok(device_ref.get_slot_field(slot, logic_typ, &self.vm)?) -// } -// -// #[wasm_bindgen(js_name = "getSlotFields", skip_typescript)] -// pub fn get_slot_fields(&self, slot: f64) -> Result { -// let device_ref = self.device; -// let fields = device_ref.get_slot_fields(slot, &self.vm)?; -// Ok(serde_wasm_bindgen::to_value(&fields).unwrap()) -// } -// -// #[wasm_bindgen(js_name = "setConnection")] -// pub fn set_connection(&self, conn: usize, net: Option) -> Result<(), JsError> { -// let device_id = self.device.id; -// self.vm -// -// .set_device_connection(device_id, conn, net)?; -// Ok(()) -// } -// -// #[wasm_bindgen(js_name = "removeDeviceFromNetwork")] -// pub fn remove_device_from_network(&self, network_id: ObjectID) -> Result { -// let id = self.device.id; -// Ok(self -// .vm -// -// .remove_device_from_network(id, network_id)?) -// } -// -// #[wasm_bindgen(js_name = "setPin")] -// pub fn set_pin(&self, pin: usize, val: Option) -> Result { -// let id = self.device.id; -// Ok(self.vm.set_pin(id, pin, val)?) -// } -// } - #[wasm_bindgen] #[derive(Debug)] pub struct VMRef { vm: Rc, } -// #[wasm_bindgen] -// pub struct ObjectRef(VMObject); - #[wasm_bindgen] impl VMRef { #[wasm_bindgen(constructor)] @@ -382,9 +57,12 @@ impl VMRef { #[wasm_bindgen(js_name = "getDevice")] pub fn get_object(&self, id: ObjectID) -> Option { - let obj = self.vm.get_object(id); - // device.map(|d| DeviceRef::from_device(d.clone(), self.vm.clone())) - obj + self.vm.get_object(id) + } + + #[wasm_bindgen(js_name = "freezeDevice")] + pub fn freeze_object(&self, id: ObjectID) -> Result { + Ok(self.vm.freeze_object(id)?) } #[wasm_bindgen(js_name = "setCode")] @@ -399,17 +77,17 @@ impl VMRef { Ok(self.vm.set_code_invalid(id, code)?) } - #[wasm_bindgen(js_name = "stepIC")] - pub fn step_ic(&self, id: ObjectID, advance_ip_on_err: bool) -> Result<(), JsError> { + #[wasm_bindgen(js_name = "stepProgrammable")] + pub fn step_programmable(&self, id: ObjectID, advance_ip_on_err: bool) -> Result<(), JsError> { Ok(self.vm.step_programmable(id, advance_ip_on_err)?) } - #[wasm_bindgen(js_name = "runIC")] - pub fn run_ic(&self, id: ObjectID, ignore_errors: bool) -> Result { + #[wasm_bindgen(js_name = "runProgrammable")] + pub fn run_programmable(&self, id: ObjectID, ignore_errors: bool) -> Result { Ok(self.vm.run_programmable(id, ignore_errors)?) } - #[wasm_bindgen(js_name = "resetIC")] + #[wasm_bindgen(js_name = "resetProgrammable")] pub fn reset_ic(&self, id: ObjectID) -> Result { Ok(self.vm.reset_programmable(id)?) } @@ -419,20 +97,25 @@ impl VMRef { *self.vm.default_network_key.borrow() } - // #[wasm_bindgen(getter)] - // pub fn devices(&self) -> Vec { - // self.vm.devices.keys().copied().collect_vec() - // } - // - // #[wasm_bindgen(getter)] - // pub fn networks(&self) -> Vec { - // self.vm.networks.keys().copied().collect_vec() - // } - // - // #[wasm_bindgen(getter)] - // pub fn ics(&self) -> Vec { - // self.vm.circuit_holders.keys().copied().collect_vec() - // } + #[wasm_bindgen(getter)] + pub fn objects(&self) -> Vec { + self.vm.objects.borrow().keys().copied().collect_vec() + } + + #[wasm_bindgen(getter)] + pub fn networks(&self) -> Vec { + self.vm.networks.borrow().keys().copied().collect_vec() + } + + #[wasm_bindgen(getter)] + pub fn circuit_holders(&self) -> Vec { + self.vm.circuit_holders.borrow().clone() + } + + #[wasm_bindgen(getter)] + pub fn program_holders(&self) -> Vec { + self.vm.program_holders.borrow().clone() + } #[wasm_bindgen(getter, js_name = "lastOperationModified")] pub fn last_operation_modified(&self) -> Vec { @@ -498,7 +181,11 @@ impl VMRef { } #[wasm_bindgen(js_name = "removeSlotOccupant")] - pub fn remove_slot_occupant(&self, id: ObjectID, index: usize) -> Result, JsError> { + pub fn remove_slot_occupant( + &self, + id: ObjectID, + index: usize, + ) -> Result, JsError> { Ok(self.vm.remove_slot_occupant(id, index)?) } @@ -512,6 +199,84 @@ impl VMRef { self.vm.restore_vm_state(state)?; Ok(()) } + + #[wasm_bindgen(js_name = "getObjectName")] + pub fn get_object_name(&self, id: ObjectID) -> Result { + let obj = self.vm.get_object(id).ok_or(VMError::UnknownId(id))?; + let name = obj.borrow().get_name().value.clone(); + Ok(name) + } + + #[wasm_bindgen(js_name = "setObjectName")] + pub fn set_object_name(&self, id: ObjectID, name: &str) -> Result<(), JsError> { + let obj = self.vm.get_object(id).ok_or(VMError::UnknownId(id))?; + obj.borrow_mut().get_mut_name().value = name.to_string(); + Ok(()) + } + + #[wasm_bindgen(js_name = "getObjectHash")] + pub fn get_object_hash(&self, id: ObjectID) -> Result { + let obj = self.vm.get_object(id).ok_or(VMError::UnknownId(id))?; + let hash = obj.borrow().get_name().hash; + Ok(hash) + } + + #[wasm_bindgen(js_name = "getObjectPrefabName")] + pub fn get_object_prefab_name(&self, id: ObjectID) -> Result { + let obj = self.vm.get_object(id).ok_or(VMError::UnknownId(id))?; + let name = obj.borrow().get_prefab().value.clone(); + Ok(name) + } + + #[wasm_bindgen(js_name = "getObjectPrefabHash")] + pub fn get_object_prefab_hash(&self, id: ObjectID) -> Result { + let obj = self.vm.get_object(id).ok_or(VMError::UnknownId(id))?; + let hash = obj.borrow().get_prefab().hash; + Ok(hash) + } + + #[wasm_bindgen(js_name = "getObjectSourceCode")] + pub fn get_object_source_code(&self, id: ObjectID) -> Result, JsError> { + let obj = self.vm.get_object(id).ok_or(VMError::UnknownId(id))?; + let code = obj + .borrow() + .as_source_code() + .map(|source| source.get_source_code()); + Ok(code) + } + + #[wasm_bindgen(js_name = "setRegister")] + pub fn set_register(&self, id: ObjectID, index: u32, val: f64) -> Result { + Ok(self.vm.set_register(id, index, val)?) + } + + #[wasm_bindgen(js_name = "setMemory")] + pub fn set_memory(&self, id: ObjectID, address: u32, val: f64) -> Result { + Ok(self.vm.set_memory(id, address, val)?) + } + + #[wasm_bindgen(js_name = "setLogicField")] + pub fn set_logic_field( + &self, + id: ObjectID, + lt: LogicType, + val: f64, + force: bool, + ) -> Result<(), JsError> { + Ok(self.vm.set_logic_field(id, lt, val, force)?) + } + + #[wasm_bindgen(js_name = "setSlotLogicField")] + pub fn set_slot_logic_field( + &self, + id: ObjectID, + slt: LogicSlotType, + index: u32, + val: f64, + force: bool, + ) -> Result<(), JsError> { + Ok(self.vm.set_slot_logic_field(id, slt, index, val, force)?) + } } impl Default for VMRef { diff --git a/ic10lsp_wasm/Cargo.toml b/ic10lsp_wasm/Cargo.toml index 45a8455..6814c4e 100644 --- a/ic10lsp_wasm/Cargo.toml +++ b/ic10lsp_wasm/Cargo.toml @@ -27,3 +27,29 @@ wasm-streams = "0.4" # web-tree-sitter-sys = "1.3" ic10lsp = { git = "https://github.com/Ryex/ic10lsp.git", branch = "wasm" } # ic10lsp = { path = "../../ic10lsp" } + +[profile.release] +# Tell `rustc` to optimize for small code size. +opt-level = "s" + +[package.metadata.wasm-pack.profile.dev] +wasm-opt = ['-O'] + +[package.metadata.wasm-pack.profile.dev.wasm-bindgen] +# Should we enable wasm-bindgen's debug assertions in its generated JS glue? +debug-js-glue = true +# Should wasm-bindgen demangle the symbols in the "name" custom section? +demangle-name-section = true +# Should we emit the DWARF debug info custom sections? +dwarf-debug-info = false +# Should we omit the default import path? +omit-default-module-path = false + +[package.metadata.wasm-pack.profile.release] +wasm-opt = ['-Oz'] + +[package.metadata.wasm-pack.profile.release.wasm-bindgen] +debug-js-glue = false +demangle-name-section = true +dwarf-debug-info = false +omit-default-module-path = false