make slots account for having occupents. return logic fields that are deived form the device or slot occupant

This commit is contained in:
Rachel Powers
2024-04-13 00:45:39 -07:00
parent 7f4a3a0470
commit d50eabe594
8 changed files with 660 additions and 267 deletions

View File

@@ -43,10 +43,15 @@ impl DeviceRef {
}
#[wasm_bindgen(getter)]
pub fn id(&self) -> u16 {
pub fn id(&self) -> u32 {
self.device.borrow().id
}
#[wasm_bindgen(getter)]
pub fn ic(&self) -> Option<u32> {
self.device.borrow().ic
}
#[wasm_bindgen(getter)]
pub fn name(&self) -> Option<String> {
self.device.borrow().name.clone()
@@ -69,12 +74,20 @@ impl DeviceRef {
#[wasm_bindgen(getter, skip_typescript)]
pub fn fields(&self) -> JsValue {
serde_wasm_bindgen::to_value(&self.device.borrow().fields).unwrap()
serde_wasm_bindgen::to_value(&self.device.borrow().get_fields(&self.vm.borrow())).unwrap()
}
#[wasm_bindgen(getter, skip_typescript)]
pub fn slots(&self) -> JsValue {
serde_wasm_bindgen::to_value(&self.device.borrow().slots).unwrap()
pub fn slots(&self) -> Vec<JsValue> {
self.device
.borrow()
.slots
.iter()
.map(|slot| {
let flat_slot: types::Slot = slot.into();
serde_wasm_bindgen::to_value(&flat_slot).unwrap()
})
.collect_vec()
}
#[wasm_bindgen(getter, skip_typescript)]
@@ -267,38 +280,37 @@ impl DeviceRef {
}
#[wasm_bindgen(js_name = "setField")]
pub fn set_field(&self, field: &str, value: f64) -> Result<f64, JsError> {
pub fn set_field(&self, field: &str, value: f64) -> Result<(), JsError> {
let logic_typ = LogicType::from_str(field)?;
let mut device_ref = self.device.borrow_mut();
let logic_field = device_ref
.fields
.get_mut(&logic_typ)
.ok_or_else(|| BindingError::InvalidEnumVariant(field.to_owned()))?;
let last = logic_field.value;
logic_field.value = value;
Ok(last)
device_ref.set_field(logic_typ, value, &self.vm.borrow())?;
Ok(())
}
#[wasm_bindgen(js_name = "setSlotField")]
pub fn set_slot_field(&self, slot: usize, field: &str, value: f64) -> Result<f64, JsError> {
pub fn set_slot_field(&self, slot: f64, field: &str, value: f64) -> Result<(), JsError> {
let logic_typ = SlotLogicType::from_str(field)?;
let mut device_ref = self.device.borrow_mut();
let slots_len = device_ref.slots.len();
let slot = device_ref
.slots
.get_mut(slot)
.ok_or(BindingError::OutOfBounds(slot, slots_len))?;
let logic_field = slot
.fields
.get_mut(&logic_typ)
.ok_or_else(|| BindingError::InvalidEnumVariant(field.to_owned()))?;
let last = logic_field.value;
logic_field.value = value;
Ok(last)
device_ref.set_slot_field(slot, logic_typ, value, &self.vm.borrow())?;
Ok(())
}
#[wasm_bindgen(js_name = "getSlotField")]
pub fn get_slot_field(&self, slot: f64, field: &str) -> Result<f64, JsError> {
let logic_typ = SlotLogicType::from_str(field)?;
let device_ref = self.device.borrow_mut();
Ok(device_ref.get_slot_field(slot, logic_typ, &self.vm.borrow())?)
}
#[wasm_bindgen(js_name = "getSlotFields", skip_typescript)]
pub fn get_slot_fields(&self, slot: f64) -> Result<JsValue, JsError> {
let device_ref = self.device.borrow_mut();
let fields = device_ref.get_slot_fields(slot, &self.vm.borrow())?;
Ok(serde_wasm_bindgen::to_value(&fields).unwrap())
}
#[wasm_bindgen(js_name = "setConnection")]
pub fn set_connection(&self, conn: usize, net: Option<u16>) -> Result<(), JsError> {
pub fn set_connection(&self, conn: usize, net: Option<u32>) -> Result<(), JsError> {
let mut device_ref = self.device.borrow_mut();
let conn_len = device_ref.connections.len();
let conn_ref = device_ref
@@ -315,19 +327,29 @@ impl DeviceRef {
}
#[wasm_bindgen(js_name = "addDeviceToNetwork")]
pub fn add_device_to_network(&self, network_id: u16, connection: usize) -> Result<bool, JsError> {
pub fn add_device_to_network(
&self,
network_id: u32,
connection: usize,
) -> Result<bool, JsError> {
let id = self.device.borrow().id;
Ok(self.vm.borrow().add_device_to_network(id, network_id, connection)?)
Ok(self
.vm
.borrow()
.add_device_to_network(id, network_id, connection)?)
}
#[wasm_bindgen(js_name = "removeDeviceFromNetwork")]
pub fn remove_device_from_network(&self, network_id: u16) -> Result<bool, JsError> {
pub fn remove_device_from_network(&self, network_id: u32) -> Result<bool, JsError> {
let id = self.device.borrow().id;
Ok(self.vm.borrow().remove_device_from_network(id, network_id)?)
Ok(self
.vm
.borrow()
.remove_device_from_network(id, network_id)?)
}
#[wasm_bindgen(js_name = "setPin")]
pub fn set_pin(&self, pin: usize, val: Option<u16>) -> Result<bool, JsError> {
pub fn set_pin(&self, pin: usize, val: Option<u32>) -> Result<bool, JsError> {
let id = self.device.borrow().id;
Ok(self.vm.borrow().set_pin(id, pin, val)?)
}
@@ -349,89 +371,98 @@ impl VM {
}
#[wasm_bindgen(js_name = "addDevice")]
pub fn add_device(&self, network: Option<u16>) -> Result<u16, JsError> {
pub fn add_device(&self, network: Option<u32>) -> Result<u32, JsError> {
Ok(self.vm.borrow_mut().add_device(network)?)
}
#[wasm_bindgen(js_name = "getDevice")]
pub fn get_device(&self, id: u16) -> Option<DeviceRef> {
pub fn get_device(&self, id: u32) -> Option<DeviceRef> {
let device = self.vm.borrow().get_device(id);
device.map(|d| DeviceRef::from_device(d.clone(), self.vm.clone()))
}
#[wasm_bindgen(js_name = "setCode")]
/// Set program code if it's valid
pub fn set_code(&self, id: u16, code: &str) -> Result<bool, JsError> {
pub fn set_code(&self, id: u32, code: &str) -> Result<bool, JsError> {
Ok(self.vm.borrow().set_code(id, code)?)
}
#[wasm_bindgen(js_name = "setCodeInvalid")]
/// Set program code and translate invalid lines to Nop, collecting errors
pub fn set_code_invalid(&self, id: u16, code: &str) -> Result<bool, JsError> {
pub fn set_code_invalid(&self, id: u32, code: &str) -> Result<bool, JsError> {
Ok(self.vm.borrow().set_code_invalid(id, code)?)
}
#[wasm_bindgen(js_name = "stepIC")]
pub fn step_ic(&self, id: u16, advance_ip_on_err: bool) -> Result<bool, JsError> {
pub fn step_ic(&self, id: u32, advance_ip_on_err: bool) -> Result<bool, JsError> {
Ok(self.vm.borrow().step_ic(id, advance_ip_on_err)?)
}
#[wasm_bindgen(js_name = "runIC")]
pub fn run_ic(&self, id: u16, ignore_errors: bool) -> Result<bool, JsError> {
pub fn run_ic(&self, id: u32, ignore_errors: bool) -> Result<bool, JsError> {
Ok(self.vm.borrow().run_ic(id, ignore_errors)?)
}
#[wasm_bindgen(js_name = "resetIC")]
pub fn reset_ic(&self, id: u16) -> Result<bool, JsError> {
pub fn reset_ic(&self, id: u32) -> Result<bool, JsError> {
Ok(self.vm.borrow().reset_ic(id)?)
}
#[wasm_bindgen(getter, js_name = "defaultNetwork")]
pub fn default_network(&self) -> u16 {
pub fn default_network(&self) -> u32 {
self.vm.borrow().default_network
}
#[wasm_bindgen(getter)]
pub fn devices(&self) -> Vec<u16> {
pub fn devices(&self) -> Vec<u32> {
self.vm.borrow().devices.keys().copied().collect_vec()
}
#[wasm_bindgen(getter)]
pub fn networks(&self) -> Vec<u16> {
pub fn networks(&self) -> Vec<u32> {
self.vm.borrow().networks.keys().copied().collect_vec()
}
#[wasm_bindgen(getter)]
pub fn ics(&self) -> Vec<u16> {
pub fn ics(&self) -> Vec<u32> {
self.vm.borrow().ics.keys().copied().collect_vec()
}
#[wasm_bindgen(getter, js_name = "lastOperationModified")]
pub fn last_operation_modified(&self) -> Vec<u16> {
pub fn last_operation_modified(&self) -> Vec<u32> {
self.vm.borrow().last_operation_modified()
}
#[wasm_bindgen(js_name = "visibleDevices")]
pub fn visible_devices(&self, source: u16) -> Vec<u16> {
pub fn visible_devices(&self, source: u32) -> Vec<u32> {
self.vm.borrow().visible_devices(source)
}
#[wasm_bindgen(js_name = "addDeviceToNetwork")]
pub fn add_device_to_network(&self, id: u16, network_id: u16, connection: usize) -> Result<bool, JsError> {
Ok(self.vm.borrow().add_device_to_network(id, network_id, connection)?)
pub fn add_device_to_network(
&self,
id: u32,
network_id: u32,
connection: usize,
) -> Result<bool, JsError> {
Ok(self
.vm
.borrow()
.add_device_to_network(id, network_id, connection)?)
}
#[wasm_bindgen(js_name = "removeDeviceFromNetwork")]
pub fn remove_device_from_network(&self, id: u16, network_id: u16) -> Result<bool, JsError> {
Ok(self.vm.borrow().remove_device_from_network(id, network_id)?)
pub fn remove_device_from_network(&self, id: u32, network_id: u32) -> Result<bool, JsError> {
Ok(self
.vm
.borrow()
.remove_device_from_network(id, network_id)?)
}
#[wasm_bindgen(js_name = "setPin")]
pub fn set_pin(&self, id: u16, pin: usize, val: Option<u16>) -> Result<bool, JsError> {
pub fn set_pin(&self, id: u32, pin: usize, val: Option<u32>) -> Result<bool, JsError> {
Ok(self.vm.borrow().set_pin(id, pin, val)?)
}
}
impl Default for VM {

View File

@@ -1,3 +1,4 @@
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
@@ -14,4 +15,45 @@ pub struct Stack(#[serde_as(as = "[_; 512]")] pub [f64; 512]);
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct Registers(#[serde_as(as = "[_; 18]")] pub [f64; 18]);
include!(concat!(env!("OUT_DIR"), "/ts_types.rs"));
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SlotOccupant {
pub id: u32,
pub prefab_hash: i32,
pub quantity: u32,
pub max_quantity: u32,
pub damage: f64,
pub fields: HashMap<ic10emu::grammar::SlotLogicType, ic10emu::LogicField>,
}
impl From<&ic10emu::SlotOccupant> for SlotOccupant {
fn from(value: &ic10emu::SlotOccupant) -> Self {
SlotOccupant {
id: value.id,
prefab_hash: value.prefab_hash,
quantity: value.quantity,
max_quantity: value.max_quantity,
damage: value.damage,
fields: value.get_fields(),
}
}
}
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct Slot {
pub typ: ic10emu::SlotType,
pub occupant: Option<SlotOccupant>,
pub fields: HashMap<ic10emu::grammar::SlotLogicType, ic10emu::LogicField>,
}
impl From<&ic10emu::Slot> for Slot {
fn from(value: &ic10emu::Slot) -> Self {
Slot {
typ: value.typ,
occupant: value.occupant.as_ref().map(|occupant| occupant.into()),
fields: value.get_fields(),
}
}
}
include!(concat!(env!("OUT_DIR"), "/ts_types.rs"));

View File

@@ -40,9 +40,18 @@ export type SlotType =
| "Torpedo"
| "None";
export interface SlotOccupant {
readonly id: number;
readonly prefab_hash: number;
readonly quantity: number;
readonly max_quantity: number;
readonly damage: number;
readonly fields: Fields;
}
export interface Slot {
typ: SlotType;
fields: Fields;
readonly typ: SlotType;
readonly occupant: SlotOccupant | undefined;
readonly fields: Fields;
}
export type Reagents = Map<string, Map<number, number>>;
@@ -50,29 +59,37 @@ export type Reagents = Map<string, Map<number, number>>;
export type Connection = { CableNetwork: number } | "Other";
export type RegisterSpec = {
RegisterSpec: { indirection: number; target: number };
readonly RegisterSpec: {
readonly indirection: number;
readonly target: number;
};
};
export type DeviceSpec = {
DeviceSpec: {
device:
readonly DeviceSpec: {
readonly device:
| "Db"
| { Numbered: number }
| { Indirect: { indirection: number; target: number } };
| { readonly Numbered: number }
| {
readonly Indirect: {
readonly indirection: number;
readonly target: number;
};
};
};
connection: number | undefined;
readonly connection: number | undefined;
};
export type LogicType = { LogicType: string };
export type SlotLogicType = { SlotLogicType: string };
export type BatchMode = { BatchMode: string };
export type ReagentMode = { ReagentMode: string };
export type Identifier = { Identifier: { name: string } };
export type LogicType = { readonly LogicType: string };
export type SlotLogicType = { readonly SlotLogicType: string };
export type BatchMode = { readonly BatchMode: string };
export type ReagentMode = { readonly ReagentMode: string };
export type Identifier = { readonly Identifier: { name: string } };
export type NumberFloat = { Float: number };
export type NumberBinary = { Binary: number };
export type NumberHexadecimal = { Hexadecimal: number };
export type NumberConstant = { Constant: number };
export type NumberString = { String: string };
export type NumberEnum = { Enum: number };
export type NumberFloat = { readonly Float: number };
export type NumberBinary = { readonly Binary: number };
export type NumberHexadecimal = { readonly Hexadecimal: number };
export type NumberConstant = { readonly Constant: number };
export type NumberString = { readonly String: string };
export type NumberEnum = { readonly Enum: number };
export type NumberOperand = {
Number:
@@ -102,18 +119,23 @@ export type Defines = Map<string, number>;
export type Pins = (number | undefined)[];
export interface Instruction {
instruction: string;
operands: Operand[];
readonly instruction: string;
readonly operands: Operand[];
}
export type ICError = {
ParseError: { line: number; start: number; end: number; msg: string };
readonly ParseError: {
readonly line: number;
readonly start: number;
readonly end: number;
readonly msg: string;
};
};
export interface Program {
instructions: Instruction[];
errors: ICError[];
labels: Map<string, number>;
readonly instructions: Instruction[];
readonly errors: ICError[];
readonly labels: Map<string, number>;
}
export interface DeviceRef {
@@ -125,4 +147,5 @@ export interface DeviceRef {
readonly defines?: Defines | undefined;
readonly pins?: Pins;
readonly program?: Program;
getSlotFields(slot: number): Fields;
}