From 29ef54ca045f5cf5cc0bfce6b2bf09c9184817e6 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Sat, 18 May 2024 04:11:38 -0700 Subject: [PATCH] refactor(vm): impl circuit holder, impl ObjectRef/Mut --- ic10emu/src/interpreter.rs | 5 + ic10emu/src/interpreter/instructions.rs | 592 ++++++++++-------- ic10emu/src/network.rs | 10 +- ic10emu/src/vm.rs | 6 +- ic10emu/src/vm/object/generic/traits.rs | 110 ++-- ic10emu/src/vm/object/macros.rs | 74 ++- ic10emu/src/vm/object/stationpedia/structs.rs | 1 + .../stationpedia/structs/circuit_holder.rs | 426 +++++++++++++ .../structs/integrated_circuit.rs | 44 +- ic10emu/src/vm/object/templates.rs | 4 +- ic10emu/src/vm/object/traits.rs | 24 +- 11 files changed, 952 insertions(+), 344 deletions(-) create mode 100644 ic10emu/src/vm/object/stationpedia/structs/circuit_holder.rs diff --git a/ic10emu/src/interpreter.rs b/ic10emu/src/interpreter.rs index 7f683d0..1c9b0e1 100644 --- a/ic10emu/src/interpreter.rs +++ b/ic10emu/src/interpreter.rs @@ -77,6 +77,11 @@ impl Program { self.instructions.len() } + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn try_from_code(code: &str) -> Result { let parse_tree = grammar::parse(code)?; let mut labels_set = HashSet::new(); diff --git a/ic10emu/src/interpreter/instructions.rs b/ic10emu/src/interpreter/instructions.rs index 82d5833..c583c53 100644 --- a/ic10emu/src/interpreter/instructions.rs +++ b/ic10emu/src/interpreter/instructions.rs @@ -865,10 +865,10 @@ impl BdseInstruction for T { let a = a.as_value(self)?; if self .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? .borrow() .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? .get_logicable_from_index(device, connection) .is_some() { @@ -885,10 +885,10 @@ impl BdsealInstruction for T { let a = a.as_value(self)?; if self .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? .borrow() .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? .get_logicable_from_index(device, connection) .is_some() { @@ -906,10 +906,10 @@ impl BrdseInstruction for T { let a = a.as_value(self)?; if self .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? .borrow() .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? .get_logicable_from_index(device, connection) .is_some() { @@ -926,10 +926,10 @@ impl BdnsInstruction for T { let a = a.as_value(self)?; if self .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? .borrow() .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? .get_logicable_from_index(device, connection) .is_none() { @@ -946,10 +946,10 @@ impl BdnsalInstruction for T { let a = a.as_value(self)?; if self .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? .borrow() .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? .get_logicable_from_index(device, connection) .is_none() { @@ -967,10 +967,10 @@ impl BrdnsInstruction for T { let a = a.as_value(self)?; if self .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? .borrow() .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? .get_logicable_from_index(device, connection) .is_none() { @@ -1341,14 +1341,16 @@ impl SdseInstruction for T { target, } = r.as_register(self)?; let (device, connection) = d.as_device(self)?; - let obj = self - .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .borrow() - .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? - .get_logicable_from_index(device, connection); - self.set_register(indirection, target, if obj.is_some() { 1.0 } else { 0.0 })?; + let is_some = { + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? + .borrow() + .as_circuit_holder() + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? + .get_logicable_from_index(device, connection) + .is_some() + }; + self.set_register(indirection, target, if is_some { 1.0 } else { 0.0 })?; Ok(()) } } @@ -1360,14 +1362,16 @@ impl SdnsInstruction for T { target, } = r.as_register(self)?; let (device, connection) = d.as_device(self)?; - let obj = self - .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .borrow() - .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? - .get_logicable_from_index(device, connection); - self.set_register(indirection, target, if obj.is_none() { 1.0 } else { 0.0 })?; + let is_none = { + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? + .borrow() + .as_circuit_holder() + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? + .get_logicable_from_index(device, connection) + .is_none() + }; + self.set_register(indirection, target, if is_none { 1.0 } else { 0.0 })?; Ok(()) } } @@ -1988,19 +1992,22 @@ impl GetInstruction for T { } = r.as_register(self)?; let address = address.as_value(self)?; let (device, connection) = d.as_device(self)?; - let obj = self - .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? .borrow() .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? .get_logicable_from_index(device, connection) - .ok_or(ICError::DeviceNotSet)?; - let obj_ref = obj.borrow(); - let memory = obj_ref - .as_memory_readable() - .ok_or(MemoryError::NotReadable)?; - self.set_register(indirection, target, memory.get_memory(address as i32)?)?; + .ok_or(ICError::DeviceNotSet) + .and_then(|obj| { + obj.map(|obj_ref| { + let val = obj_ref + .as_memory_readable() + .ok_or(MemoryError::NotWriteable)? + .get_memory(address as i32)?; + self.set_register(indirection, target, val) + }) + })?; Ok(()) } } @@ -2019,19 +2026,22 @@ impl GetdInstruction for T { } = r.as_register(self)?; let id = id.as_value(self)?; let address = address.as_value(self)?; - let obj = self - .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? .borrow() .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? .get_logicable_from_id(id as ObjectID, None) - .ok_or(ICError::DeviceNotSet)?; - let obj_ref = obj.borrow(); - let memory = obj_ref - .as_memory_readable() - .ok_or(MemoryError::NotReadable)?; - self.set_register(indirection, target, memory.get_memory(address as i32)?)?; + .ok_or(ICError::DeviceNotSet) + .and_then(|obj| { + obj.map(|obj_ref| { + let val = obj_ref + .as_memory_readable() + .ok_or(MemoryError::NotWriteable)? + .get_memory(address as i32)?; + self.set_register(indirection, target, val) + }) + })?; Ok(()) } } @@ -2047,19 +2057,22 @@ impl PutInstruction for T { let (device, connection) = d.as_device(self)?; let address = address.as_value(self)?; let value = value.as_value(self)?; - let obj = self - .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .borrow() - .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? - .get_logicable_from_index(device, connection) - .ok_or(ICError::DeviceNotSet)?; - let mut obj_ref = obj.borrow_mut(); - let memory = obj_ref - .as_mut_memory_writable() - .ok_or(MemoryError::NotWriteable)?; - memory.set_memory(address as i32, value)?; + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? + .borrow_mut() + .as_mut_circuit_holder() + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? + .get_logicable_from_index_mut(device, connection) + .ok_or(ICError::DeviceNotSet) + .and_then(|mut obj| { + obj.map(|obj_ref| { + obj_ref + .as_mut_memory_writable() + .ok_or(MemoryError::NotWriteable)? + .set_memory(address as i32, value) + .map_err(Into::into) + }) + })?; Ok(()) } } @@ -2075,19 +2088,22 @@ impl PutdInstruction for T { let id = id.as_value(self)?; let address = address.as_value(self)?; let value = value.as_value(self)?; - let obj = self - .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .borrow() - .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? - .get_logicable_from_id(id as ObjectID, None) - .ok_or(ICError::DeviceNotSet)?; - let mut obj_ref = obj.borrow_mut(); - let memory = obj_ref - .as_mut_memory_writable() - .ok_or(MemoryError::NotWriteable)?; - memory.set_memory(address as i32, value)?; + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? + .borrow_mut() + .as_mut_circuit_holder() + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? + .get_logicable_from_id_mut(id as ObjectID, None) + .ok_or(ICError::DeviceNotSet) + .and_then(|mut obj| { + obj.map(|obj_ref| { + obj_ref + .as_mut_memory_writable() + .ok_or(MemoryError::NotWriteable)? + .set_memory(address as i32, value) + .map_err(Into::into) + }) + })?; Ok(()) } } @@ -2096,19 +2112,22 @@ impl ClrInstruction for T { /// clr d? fn execute_inner(&mut self, d: &InstOperand) -> Result<(), ICError> { let (device, connection) = d.as_device(self)?; - let obj = self - .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .borrow() - .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? - .get_logicable_from_index(device, connection) - .ok_or(ICError::DeviceNotSet)?; - let mut obj_ref = obj.borrow_mut(); - let memory = obj_ref - .as_mut_memory_writable() - .ok_or(MemoryError::NotWriteable)?; - memory.clear_memory()?; + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? + .borrow_mut() + .as_mut_circuit_holder() + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? + .get_logicable_from_index_mut(device, connection) + .ok_or(ICError::DeviceNotSet) + .and_then(|mut obj| { + obj.map(|obj_ref| { + obj_ref + .as_mut_memory_writable() + .ok_or(MemoryError::NotWriteable)? + .clear_memory() + .map_err(Into::into) + }) + })?; Ok(()) } } @@ -2116,19 +2135,22 @@ impl ClrdInstruction for T { /// clrd id(r?|num) fn execute_inner(&mut self, id: &InstOperand) -> Result<(), ICError> { let id = id.as_value(self)?; - let obj = self - .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .borrow() - .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? - .get_logicable_from_id(id as ObjectID, None) - .ok_or(ICError::DeviceNotSet)?; - let mut obj_ref = obj.borrow_mut(); - let memory = obj_ref - .as_mut_memory_writable() - .ok_or(MemoryError::NotWriteable)?; - memory.clear_memory()?; + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? + .borrow_mut() + .as_mut_circuit_holder() + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? + .get_logicable_from_id_mut(id as ObjectID, None) + .ok_or(ICError::DeviceNotSet) + .and_then(|mut obj| { + obj.map(|obj_ref| { + obj_ref + .as_mut_memory_writable() + .ok_or(MemoryError::NotWriteable)? + .clear_memory() + .map_err(Into::into) + }) + })?; Ok(()) } } @@ -2144,23 +2166,30 @@ impl SInstruction for T { let (device, connection) = d.as_device(self)?; let logic_type = logic_type.as_logic_type(self)?; let val = r.as_value(self)?; - let obj = self - .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .borrow() - .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? - .get_logicable_from_index(device, connection) - .ok_or(ICError::DeviceNotSet)?; - let mut obj_ref = obj.borrow_mut(); - let device_id = obj_ref.get_id(); - let logicable = obj_ref - .as_mut_logicable() - .ok_or(ICError::NotLogicable(device_id))?; - if !logicable.can_logic_write(logic_type) { - return Err(LogicError::CantWrite(logic_type).into()); - } - logicable.set_logic(logic_type, val, false)?; + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? + .borrow_mut() + .as_mut_circuit_holder() + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? + .get_logicable_from_index_mut(device, connection) + .ok_or(ICError::DeviceNotSet) + .and_then(|mut obj| { + let obj_id = obj.get_id(); + obj.map(|obj_ref| { + obj_ref + .as_mut_logicable() + .ok_or(ICError::NotLogicable(obj_id)) + .and_then(|logicable| { + if !logicable.can_logic_write(logic_type) { + Err(LogicError::CantWrite(logic_type).into()) + } else { + logicable + .set_logic(logic_type, val, false) + .map_err(Into::into) + } + }) + }) + })?; Ok(()) } } @@ -2176,23 +2205,30 @@ impl SdInstruction for T { let id = id.as_value(self)?; let logic_type = logic_type.as_logic_type(self)?; let val = r.as_value(self)?; - let obj = self - .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .borrow() - .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? - .get_logicable_from_id(id as ObjectID, None) - .ok_or(ICError::DeviceNotSet)?; - let mut obj_ref = obj.borrow_mut(); - let device_id = obj_ref.get_id(); - let logicable = obj_ref - .as_mut_logicable() - .ok_or(ICError::NotLogicable(device_id))?; - if !logicable.can_logic_write(logic_type) { - return Err(LogicError::CantWrite(logic_type).into()); - } - logicable.set_logic(logic_type, val, false)?; + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? + .borrow_mut() + .as_mut_circuit_holder() + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? + .get_logicable_from_id_mut(id as ObjectID, None) + .ok_or(ICError::DeviceNotSet) + .and_then(|mut obj| { + let obj_id = obj.get_id(); + obj.map(|obj_ref| { + obj_ref + .as_mut_logicable() + .ok_or(ICError::NotLogicable(obj_id)) + .and_then(|logicable| { + if !logicable.can_logic_write(logic_type) { + Err(LogicError::CantWrite(logic_type).into()) + } else { + logicable + .set_logic(logic_type, val, false) + .map_err(Into::into) + } + }) + }) + })?; Ok(()) } } @@ -2210,27 +2246,30 @@ impl SsInstruction for T { let slot_index = slot_index.as_value(self)?; let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; let val = r.as_value(self)?; - let obj = self - .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .borrow() - .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? - .get_logicable_from_index(device, connection) - .ok_or(ICError::DeviceNotSet)?; - let mut obj_ref = obj.borrow_mut(); - let device_id = obj_ref.get_id(); - let logicable = obj_ref - .as_mut_logicable() - .ok_or(ICError::NotLogicable(device_id))?; - let device_id = logicable.get_id(); - let device = logicable - .as_mut_device() - .ok_or(ICError::NotSlotWriteable(device_id))?; - if !device.can_slot_logic_write(logic_slot_type, slot_index) { - return Err(LogicError::CantSlotWrite(logic_slot_type, slot_index).into()); - } - device.set_slot_logic(logic_slot_type, slot_index, val, false)?; + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? + .borrow_mut() + .as_mut_circuit_holder() + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? + .get_logicable_from_index_mut(device, connection) + .ok_or(ICError::DeviceNotSet) + .and_then(|mut obj| { + let obj_id = obj.get_id(); + obj.map(|obj_ref| { + obj_ref + .as_mut_device() + .ok_or(ICError::NotLogicable(obj_id)) + .and_then(|logicable| { + if !logicable.can_slot_logic_write(logic_slot_type, slot_index) { + Err(LogicError::CantSlotWrite(logic_slot_type, slot_index).into()) + } else { + logicable + .set_slot_logic(logic_slot_type, slot_index, val, false) + .map_err(Into::into) + } + }) + }) + })?; Ok(()) } } @@ -2248,7 +2287,7 @@ impl SbInstruction for T { let logic_type = logic_type.as_logic_type(self)?; let val = r.as_value(self)?; self.get_vm() - .set_batch_device_field(self.get_id(), prefab, logic_type, val, false)?; + .set_batch_device_field(*self.get_id(), prefab, logic_type, val, false)?; Ok(()) } } @@ -2268,7 +2307,7 @@ impl SbsInstruction for T { let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; let val = r.as_value(self)?; self.get_vm().set_batch_device_slot_field( - self.get_id(), + *self.get_id(), prefab, slot_index, logic_slot_type, @@ -2294,7 +2333,7 @@ impl SbnInstruction for T { let logic_type = logic_type.as_logic_type(self)?; let val = r.as_value(self)?; self.get_vm().set_batch_name_device_field( - self.get_id(), + *self.get_id(), prefab, name, logic_type, @@ -2320,22 +2359,29 @@ impl LInstruction for T { } = r.as_register(self)?; let (device, connection) = d.as_device(self)?; let logic_type = logic_type.as_logic_type(self)?; - let obj = self + let val = self .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? .borrow() .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? .get_logicable_from_index(device, connection) - .ok_or(ICError::DeviceNotSet)?; - let obj_ref = obj.borrow(); - let logicable = obj_ref - .as_logicable() - .ok_or(ICError::NotLogicable(obj_ref.get_id()))?; - if !logicable.can_logic_read(logic_type) { - return Err(LogicError::CantRead(logic_type).into()); - } - self.set_register(indirection, target, logicable.get_logic(logic_type)?)?; + .ok_or(ICError::DeviceNotSet) + .and_then(|obj| { + obj.map(|obj_ref| { + obj_ref + .as_logicable() + .ok_or(ICError::NotLogicable(*obj_ref.get_id())) + .and_then(|logicable| { + if !logicable.can_logic_read(logic_type) { + Err(LogicError::CantRead(logic_type).into()) + } else { + logicable.get_logic(logic_type).map_err(Into::into) + } + }) + }) + })?; + self.set_register(indirection, target, val)?; Ok(()) } } @@ -2354,22 +2400,29 @@ impl LdInstruction for T { } = r.as_register(self)?; let id = id.as_value(self)?; let logic_type = logic_type.as_logic_type(self)?; - let obj = self + let val = self .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? .borrow() .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? .get_logicable_from_id(id as ObjectID, None) - .ok_or(ICError::DeviceNotSet)?; - let obj_ref = obj.borrow(); - let logicable = obj_ref - .as_logicable() - .ok_or(ICError::NotLogicable(obj_ref.get_id()))?; - if !logicable.can_logic_read(logic_type) { - return Err(LogicError::CantRead(logic_type).into()); - } - self.set_register(indirection, target, logicable.get_logic(logic_type)?)?; + .ok_or(ICError::DeviceNotSet) + .and_then(|obj| { + obj.map(|obj_ref| { + obj_ref + .as_logicable() + .ok_or(ICError::NotLogicable(*obj_ref.get_id())) + .and_then(|logicable| { + if !logicable.can_logic_read(logic_type) { + Err(LogicError::CantRead(logic_type).into()) + } else { + logicable.get_logic(logic_type).map_err(Into::into) + } + }) + }) + })?; + self.set_register(indirection, target, val)?; Ok(()) } } @@ -2390,26 +2443,31 @@ impl LsInstruction for T { let (device, connection) = d.as_device(self)?; let slot_index = slot_index.as_value(self)?; let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; - let obj = self + let val = self .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? .borrow() .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? .get_logicable_from_index(device, connection) - .ok_or(ICError::DeviceNotSet)?; - let obj_ref = obj.borrow(); - let logicable = obj_ref - .as_logicable() - .ok_or(ICError::NotLogicable(obj_ref.get_id()))?; - if !logicable.can_slot_logic_read(logic_slot_type, slot_index) { - return Err(LogicError::CantSlotRead(logic_slot_type, slot_index).into()); - } - self.set_register( - indirection, - target, - logicable.get_slot_logic(logic_slot_type, slot_index)?, - )?; + .ok_or(ICError::DeviceNotSet) + .and_then(|obj| { + obj.map(|obj_ref| { + obj_ref + .as_logicable() + .ok_or(ICError::NotLogicable(*obj_ref.get_id())) + .and_then(|logicable| { + if !logicable.can_slot_logic_read(logic_slot_type, slot_index) { + Err(LogicError::CantSlotRead(logic_slot_type, slot_index).into()) + } else { + logicable + .get_slot_logic(logic_slot_type, slot_index) + .map_err(Into::into) + } + }) + }) + })?; + self.set_register(indirection, target, val)?; Ok(()) } } @@ -2430,66 +2488,70 @@ impl LrInstruction for T { let (device, connection) = d.as_device(self)?; let reagent_mode = reagent_mode.as_reagent_mode(self)?; let int = int.as_value(self)?; - let obj = self + let val = self .get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? .borrow() .as_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? .get_logicable_from_index(device, connection) - .ok_or(ICError::DeviceNotSet)?; - let obj_ref = obj.borrow(); - let logicable = obj_ref - .as_logicable() - .ok_or(ICError::NotLogicable(obj_ref.get_id()))?; - - let result = match reagent_mode { - LogicReagentMode::Contents => { - let device = logicable - .as_device() - .ok_or(ICError::NotReagentReadable(logicable.get_id()))?; - device - .get_reagents() - .iter() - .find(|(hash, _)| *hash as f64 == int) - .map(|(_, quantity)| *quantity) - .unwrap_or(0.0) - } - LogicReagentMode::TotalContents => { - let device = logicable - .as_device() - .ok_or(ICError::NotReagentReadable(logicable.get_id()))?; - device - .get_reagents() - .iter() - .map(|(_, quantity)| quantity) - .sum() - } - LogicReagentMode::Required => { - let reagent_interface = logicable - .as_reagent_interface() - .ok_or(ICError::NotReagentReadable(logicable.get_id()))?; - reagent_interface - .get_current_required() - .iter() - .find(|(hash, _)| *hash as f64 == int) - .map(|(_, quantity)| *quantity) - .unwrap_or(0.0) - } - LogicReagentMode::Recipe => { - let reagent_interface = logicable - .as_reagent_interface() - .ok_or(ICError::NotReagentReadable(logicable.get_id()))?; - reagent_interface - .get_current_recipie() - .iter() - .find(|(hash, _)| *hash as f64 == int) - .map(|(_, quantity)| *quantity) - .unwrap_or(0.0) - } - }; - - self.set_register(indirection, target, result)?; + .ok_or(ICError::DeviceNotSet) + .and_then(|obj| { + obj.map(|obj_ref| { + obj_ref + .as_logicable() + .ok_or(ICError::NotLogicable(*obj_ref.get_id())) + .and_then(|logicable| { + let result = match reagent_mode { + LogicReagentMode::Contents => { + let device = logicable + .as_device() + .ok_or(ICError::NotReagentReadable(*logicable.get_id()))?; + device + .get_reagents() + .iter() + .find(|(hash, _)| *hash as f64 == int) + .map(|(_, quantity)| *quantity) + .unwrap_or(0.0) + } + LogicReagentMode::TotalContents => { + let device = logicable + .as_device() + .ok_or(ICError::NotReagentReadable(*logicable.get_id()))?; + device + .get_reagents() + .iter() + .map(|(_, quantity)| quantity) + .sum() + } + LogicReagentMode::Required => { + let reagent_interface = logicable + .as_reagent_interface() + .ok_or(ICError::NotReagentReadable(*logicable.get_id()))?; + reagent_interface + .get_current_required() + .iter() + .find(|(hash, _)| *hash as f64 == int) + .map(|(_, quantity)| *quantity) + .unwrap_or(0.0) + } + LogicReagentMode::Recipe => { + let reagent_interface = logicable + .as_reagent_interface() + .ok_or(ICError::NotReagentReadable(*logicable.get_id()))?; + reagent_interface + .get_current_recipie() + .iter() + .find(|(hash, _)| *hash as f64 == int) + .map(|(_, quantity)| *quantity) + .unwrap_or(0.0) + } + }; + Ok(result) + }) + }) + })?; + self.set_register(indirection, target, val)?; Ok(()) } } @@ -2513,7 +2575,7 @@ impl LbInstruction for T { let batch_mode = batch_mode.as_batch_mode(self)?; let val = self.get_vm() - .get_batch_device_field(self.get_id(), prefab, logic_type, batch_mode)?; + .get_batch_device_field(*self.get_id(), prefab, logic_type, batch_mode)?; self.set_register(indirection, target, val)?; Ok(()) } @@ -2539,7 +2601,7 @@ impl LbnInstruction for T { let logic_type = logic_type.as_logic_type(self)?; let batch_mode = batch_mode.as_batch_mode(self)?; let val = self.get_vm().get_batch_name_device_field( - self.get_id(), + *self.get_id(), prefab, name, logic_type, @@ -2572,7 +2634,7 @@ impl LbnsInstruction for T { let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; let batch_mode = batch_mode.as_batch_mode(self)?; let val = self.get_vm().get_batch_name_device_slot_field( - self.get_id(), + *self.get_id(), prefab, name, slot_index, @@ -2604,7 +2666,7 @@ impl LbsInstruction for T { let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; let batch_mode = batch_mode.as_batch_mode(self)?; let val = self.get_vm().get_batch_device_slot_field( - self.get_id(), + *self.get_id(), prefab, slot_index, logic_slot_type, @@ -2618,12 +2680,14 @@ impl LbsInstruction for T { impl HcfInstruction for T { /// hcf fn execute_inner(&mut self) -> Result<(), ICError> { - self.get_circuit_holder() - .ok_or(ICError::NoCircuitHolder(self.get_id()))? - .borrow_mut() - .as_mut_circuit_holder() - .ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? - .hault_and_catch_fire(); + { + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(*self.get_id()))? + .borrow_mut() + .as_mut_circuit_holder() + .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))? + .hault_and_catch_fire(); + } self.set_state(ICState::HasCaughtFire); Ok(()) } diff --git a/ic10emu/src/network.rs b/ic10emu/src/network.rs index c4f8b0d..e0027c5 100644 --- a/ic10emu/src/network.rs +++ b/ic10emu/src/network.rs @@ -235,11 +235,11 @@ impl Storage for CableNetwork { fn get_slot_mut(&mut self, _index: usize) -> Option<&mut crate::vm::object::Slot> { None } - fn get_slots(&self) -> &[crate::vm::object::Slot] { - &[] + fn get_slots(&self) -> Vec<&crate::vm::object::Slot> { + vec![] } - fn get_slots_mut(&mut self) -> &mut [crate::vm::object::Slot] { - &mut [] + fn get_slots_mut(&mut self) -> Vec<&mut crate::vm::object::Slot> { + vec![] } } @@ -422,7 +422,7 @@ where impl From> for FrozenCableNetwork { fn from(value: NetworkRef) -> Self { FrozenCableNetwork { - id: value.get_id(), + id: *value.get_id(), devices: value.get_devices(), power_only: value.get_power_only(), channels: *value.get_channel_data(), diff --git a/ic10emu/src/vm.rs b/ic10emu/src/vm.rs index 3838e90..484f5da 100644 --- a/ic10emu/src/vm.rs +++ b/ic10emu/src/vm.rs @@ -617,7 +617,7 @@ impl VM { ) -> Result<(), ICError> { self.batch_device(source, prefab, None) .map(|device| { - self.set_modified(device.borrow().get_id()); + self.set_modified(*device.borrow().get_id()); device .borrow_mut() .as_mut_device() @@ -639,7 +639,7 @@ impl VM { ) -> Result<(), ICError> { self.batch_device(source, prefab, None) .map(|device| { - self.set_modified(device.borrow().get_id()); + self.set_modified(*device.borrow().get_id()); device .borrow_mut() .as_mut_device() @@ -661,7 +661,7 @@ impl VM { ) -> Result<(), ICError> { self.batch_device(source, prefab, Some(name)) .map(|device| { - self.set_modified(device.borrow().get_id()); + self.set_modified(*device.borrow().get_id()); device .borrow_mut() .as_mut_device() diff --git a/ic10emu/src/vm/object/generic/traits.rs b/ic10emu/src/vm/object/generic/traits.rs index 780ab9b..ff8338d 100644 --- a/ic10emu/src/vm/object/generic/traits.rs +++ b/ic10emu/src/vm/object/generic/traits.rs @@ -41,11 +41,11 @@ impl Storage for T { fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot> { self.slots_mut().get_mut(index) } - fn get_slots(&self) -> &[Slot] { - self.slots() + fn get_slots(&self) -> Vec<&Slot> { + self.slots().iter().collect() } - fn get_slots_mut(&mut self) -> &mut [Slot] { - self.slots_mut() + fn get_slots_mut(&mut self) -> Vec<&mut Slot> { + self.slots_mut().iter_mut().collect() } } @@ -63,57 +63,77 @@ impl Logicable for T { self.get_name().hash } fn is_logic_readable(&self) -> bool { - LogicType::iter().any(|lt| self.can_logic_read(lt)) + true } fn is_logic_writeable(&self) -> bool { LogicType::iter().any(|lt| self.can_logic_write(lt)) } fn can_logic_read(&self, lt: LogicType) -> bool { - self.fields() - .get(<) - .map(|field| { - matches!( - field.field_type, - MemoryAccess::Read | MemoryAccess::ReadWrite - ) - }) - .unwrap_or(false) + match lt { + LogicType::PrefabHash | LogicType::NameHash | LogicType::ReferenceId => true, + _ => self + .fields() + .get(<) + .map(|field| { + matches!( + field.field_type, + MemoryAccess::Read | MemoryAccess::ReadWrite + ) + }) + .unwrap_or(false), + } } fn can_logic_write(&self, lt: LogicType) -> bool { - self.fields() - .get(<) - .map(|field| { - matches!( - field.field_type, - MemoryAccess::Write | MemoryAccess::ReadWrite - ) - }) - .unwrap_or(false) + match lt { + LogicType::PrefabHash | LogicType::NameHash | LogicType::ReferenceId => false, + _ => self + .fields() + .get(<) + .map(|field| { + matches!( + field.field_type, + MemoryAccess::Write | MemoryAccess::ReadWrite + ) + }) + .unwrap_or(false), + } } fn get_logic(&self, lt: LogicType) -> Result { - self.fields() - .get(<) - .and_then(|field| match field.field_type { - MemoryAccess::Read | MemoryAccess::ReadWrite => Some(field.value), - _ => None, - }) - .ok_or(LogicError::CantRead(lt)) + match lt { + LogicType::PrefabHash => Ok(self.get_prefab().hash as f64), + LogicType::NameHash => Ok(self.get_name().hash as f64), + LogicType::ReferenceId => Ok(*self.get_id() as f64), + _ => self + .fields() + .get(<) + .and_then(|field| match field.field_type { + MemoryAccess::Read | MemoryAccess::ReadWrite => Some(field.value), + _ => None, + }) + .ok_or(LogicError::CantRead(lt)), + } } fn set_logic(&mut self, lt: LogicType, value: f64, force: bool) -> Result<(), LogicError> { - self.fields_mut() - .get_mut(<) - .ok_or(LogicError::CantWrite(lt)) - .and_then(|field| match field.field_type { - MemoryAccess::Write | MemoryAccess::ReadWrite => { - field.value = value; - Ok(()) - } - _ if force => { - field.value = value; - Ok(()) - } - _ => Err(LogicError::CantWrite(lt)), - }) + match lt { + LogicType::PrefabHash | LogicType::NameHash | LogicType::ReferenceId => { + Err(LogicError::CantWrite(lt)) + } + _ => self + .fields_mut() + .get_mut(<) + .ok_or(LogicError::CantWrite(lt)) + .and_then(|field| match field.field_type { + MemoryAccess::Write | MemoryAccess::ReadWrite => { + field.value = value; + Ok(()) + } + _ if force => { + field.value = value; + Ok(()) + } + _ => Err(LogicError::CantWrite(lt)), + }), + } } fn can_slot_logic_read(&self, slt: LogicSlotType, index: f64) -> bool { if index < 0.0 { @@ -200,7 +220,7 @@ impl Logicable for T { } ReferenceId => { if let Some(occupant) = occupant { - Ok(occupant.borrow().get_id() as f64) + Ok(*occupant.borrow().get_id() as f64) } else { Ok(0.0) } diff --git a/ic10emu/src/vm/object/macros.rs b/ic10emu/src/vm/object/macros.rs index 825506f..2712d3d 100644 --- a/ic10emu/src/vm/object/macros.rs +++ b/ic10emu/src/vm/object/macros.rs @@ -8,7 +8,7 @@ macro_rules! object_trait { } }; (@body $trait_name:ident { $($trt:ident),* }; ) => { - fn get_id(&self) -> crate::vm::object::ObjectID; + fn get_id(&self) -> &crate::vm::object::ObjectID; fn set_id(&mut self, id: crate::vm::object::ObjectID); fn get_prefab(&self) -> &crate::vm::object::Name; fn get_mut_prefab(&mut self) -> &mut crate::vm::object::Name; @@ -53,6 +53,74 @@ macro_rules! object_trait { } } + pub enum [<$trait_name Ref>]<'a> { + DynRef(&'a dyn $trait_name), + VMObject(crate::vm::object::VMObject), + } + + impl<'a> [<$trait_name Ref>]<'a> { + pub fn from_ref(reference: &'a dyn $trait_name) -> Self { + Self::DynRef(reference) + } + pub fn from_vm_object(obj: crate::vm::object::VMObject) -> Self { + Self::VMObject(obj) + } + pub fn get_id(&self) -> u32 { + match self { + Self::DynRef(reference) => *reference.get_id(), + Self::VMObject(obj) => *obj.borrow().get_id(), + + } + } + /// call func on the dyn refrence or a borrow of the vm object + pub fn map(&self, mut func: F ) -> R + where + F: std::ops::FnMut(& dyn $trait_name) -> R + { + match self { + Self::DynRef(reference) => func(*reference), + Self::VMObject(obj) => { + let obj_ref = obj.borrow(); + func(&*obj_ref) + } + } + } + } + + pub enum [<$trait_name RefMut>]<'a> { + DynRef(&'a mut dyn $trait_name), + VMObject(crate::vm::object::VMObject), + } + + impl<'a> [<$trait_name RefMut>]<'a> { + pub fn from_ref(reference: &'a mut dyn $trait_name) -> Self { + Self::DynRef(reference) + } + pub fn from_vm_object(obj: crate::vm::object::VMObject) -> Self { + Self::VMObject(obj) + } + pub fn get_id(&self) -> u32 { + match self { + Self::DynRef(refrence) => *refrence.get_id(), + Self::VMObject(obj) => *obj.borrow().get_id(), + + } + } + /// call func on the dyn refrence or a borrow of the vm object + pub fn map(&mut self, mut func: F ) -> R + where + F: std::ops::FnMut(&mut dyn $trait_name) -> R + { + match self { + Self::DynRef(reference) => func(*reference), + Self::VMObject(obj) => { + let mut obj_ref = obj.borrow_mut(); + func(&mut *obj_ref) + } + } + } + } + } }; ( $trait_name:ident $(: $($bound:tt)* )? {$($trt:ident),*}) => { @@ -95,8 +163,8 @@ macro_rules! ObjectInterface { } => { impl $trait_name for $struct { - fn get_id(&self) -> crate::vm::object::ObjectID { - self.$id_field + fn get_id(&self) -> &crate::vm::object::ObjectID { + &self.$id_field } fn set_id(&mut self, id: crate::vm::object::ObjectID) { diff --git a/ic10emu/src/vm/object/stationpedia/structs.rs b/ic10emu/src/vm/object/stationpedia/structs.rs index a51cd85..b2cd51e 100644 --- a/ic10emu/src/vm/object/stationpedia/structs.rs +++ b/ic10emu/src/vm/object/stationpedia/structs.rs @@ -1,3 +1,4 @@ mod integrated_circuit; +mod circuit_holder; pub use integrated_circuit::ItemIntegratedCircuit10; diff --git a/ic10emu/src/vm/object/stationpedia/structs/circuit_holder.rs b/ic10emu/src/vm/object/stationpedia/structs/circuit_holder.rs new file mode 100644 index 0000000..230fb9a --- /dev/null +++ b/ic10emu/src/vm/object/stationpedia/structs/circuit_holder.rs @@ -0,0 +1,426 @@ +use crate::{ + network::{CableConnectionType, Connection, ConnectionRole}, + vm::{ + enums::{ + basic_enums::Class as SlotClass, + prefabs::StationpediaPrefab, + script_enums::{LogicSlotType, LogicType}, + }, + object::{ + errors::LogicError, macros::ObjectInterface, traits::*, Name, ObjectID, Slot, VMObject, + }, + VM, + }, +}; +use macro_rules_attribute::derive; +use std::rc::Rc; +use strum::EnumProperty; + +#[derive(ObjectInterface!)] +#[custom(implements(Object { Structure, Device, Storage, Logicable, CircuitHolder }))] +pub struct StructureCircuitHousing { + #[custom(object_id)] + pub id: ObjectID, + #[custom(object_prefab)] + pub prefab: Name, + #[custom(object_name)] + pub name: Name, + #[custom(object_vm_ref)] + pub vm: Rc, + pub error: i32, + pub on: bool, + pub setting: f64, + pub slot: Slot, + pub pins: [Option; 6], + pub connections: [crate::network::Connection; 2], +} + +#[allow(dead_code)] +impl StructureCircuitHousing { + pub fn new(id: ObjectID, vm: Rc) -> Self { + StructureCircuitHousing { + id, + prefab: Name { + value: StationpediaPrefab::StructureCircuitHousing.to_string(), + hash: StationpediaPrefab::StructureCircuitHousing as i32, + }, + name: Name::new( + StationpediaPrefab::StructureCircuitHousing + .get_str("name") + .unwrap(), + ), + vm, + error: 0, + on: true, + setting: 0.0, + slot: Slot { + parent: id, + index: 0, + name: "Programmable Chip".to_string(), + typ: SlotClass::ProgrammableChip, + readable_logic: vec![ + LogicSlotType::Class, + LogicSlotType::Damage, + LogicSlotType::LineNumber, + LogicSlotType::MaxQuantity, + LogicSlotType::OccupantHash, + LogicSlotType::Occupied, + LogicSlotType::PrefabHash, + LogicSlotType::Quantity, + LogicSlotType::ReferenceId, + LogicSlotType::SortingClass, + ], + writeable_logic: vec![], + occupant: None, + quantity: 0, + }, + pins: [None, None, None, None, None, None], + connections: [ + Connection::CableNetwork { + net: None, + typ: CableConnectionType::Data, + role: ConnectionRole::Input, + }, + Connection::CableNetwork { + net: None, + typ: CableConnectionType::Power, + role: ConnectionRole::None, + }, + ], + } + } +} + +impl Structure for StructureCircuitHousing { + fn is_small_grid(&self) -> bool { + true + } +} + +impl Storage for StructureCircuitHousing { + fn slots_count(&self) -> usize { + 1 + } + fn get_slot(&self, index: usize) -> Option<&Slot> { + if index != 0 { + None + } else { + Some(&self.slot) + } + } + fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot> { + if index != 0 { + None + } else { + Some(&mut self.slot) + } + } + fn get_slots(&self) -> Vec<&Slot> { + vec![&self.slot] + } + fn get_slots_mut(&mut self) -> Vec<&mut Slot> { + vec![&mut self.slot] + } +} + +impl Logicable for StructureCircuitHousing { + fn prefab_hash(&self) -> i32 { + self.get_prefab().hash + } + fn name_hash(&self) -> i32 { + self.get_name().hash + } + fn is_logic_readable(&self) -> bool { + true + } + fn is_logic_writeable(&self) -> bool { + true + } + fn can_logic_read(&self, lt: LogicType) -> bool { + use LogicType::*; + matches!(lt, Error | LineNumber | NameHash | On | Power | PrefabHash | ReferenceId + | RequiredPower | Setting) + } + fn can_logic_write(&self, lt: LogicType) -> bool { + use LogicType::*; + matches!(lt, LineNumber | On | Setting) + } + fn get_logic(&self, lt: LogicType) -> Result { + match lt { + LogicType::PrefabHash => Ok(self.get_prefab().hash as f64), + LogicType::NameHash => Ok(self.get_name().hash as f64), + LogicType::ReferenceId => Ok(*self.get_id() as f64), + LogicType::Error => Ok(self.error as f64), + LogicType::LineNumber => { + let result = self + .slot + .occupant + .and_then(|id| { + self.vm + .get_object(id) + .and_then(|obj| { + obj.borrow() + .as_logicable() + .map(|logicable| logicable.get_logic(LogicType::LineNumber)) + }) + }); + result.unwrap_or(Ok(0.0)) + } + LogicType::On => Ok(self.on as i32 as f64), + LogicType::Power => { + if let Connection::CableNetwork { net, .. } = self.connections[1] { + if net.is_some() { + Ok(1.0) + } else { + Ok(0.0) + } + } else { + Ok(0.0) + } + } + LogicType::RequiredPower => { + if let Connection::CableNetwork { net, .. } = self.connections[1] { + if net.is_some() { + if self.on { + Ok(10.0) + } else { + Ok(0.0) + } + } else { + Ok(-1.0) + } + } else { + Ok(-1.0) + } + } // 10 if on + LogicType::Setting => Ok(self.setting), + _ => Err(LogicError::CantRead(lt)), + } + } + fn set_logic(&mut self, lt: LogicType, value: f64, force: bool) -> Result<(), LogicError> { + match lt { + LogicType::LineNumber => self + .slot + .occupant + .and_then(|id| { + self.vm + .get_object(id) + .and_then(|obj| { + obj.borrow_mut().as_mut_logicable().map(|logicable| { + logicable.set_logic(LogicType::LineNumber, value, force) + }) + }) + }) + .unwrap_or(Err(LogicError::CantWrite(lt))), + LogicType::On => { + self.on = value != 0.0; + Ok(()) + } + LogicType::Setting => { + self.setting = value; + Ok(()) + } + _ => Err(LogicError::CantWrite(lt)), + } + } + fn can_slot_logic_read(&self, _slt: LogicSlotType, _indexx: f64) -> bool { + false + } + fn get_slot_logic(&self, _slt: LogicSlotType, index: f64) -> Result { + Err(LogicError::SlotIndexOutOfRange(index, self.slots_count())) + } + fn valid_logic_types(&self) -> Vec { + use LogicType::*; + vec![ + Error, + LineNumber, + NameHash, + On, + Power, + PrefabHash, + ReferenceId, + RequiredPower, + Setting, + ] + } + fn known_modes(&self) -> Option> { + None + } +} + +impl Device for StructureCircuitHousing { + fn has_reagents(&self) -> bool { + false + } + fn has_atmosphere(&self) -> bool { + false + } + fn has_lock_state(&self) -> bool { + false + } + fn has_mode_state(&self) -> bool { + false + } + fn has_open_state(&self) -> bool { + false + } + fn has_color_state(&self) -> bool { + false + } + fn has_activate_state(&self) -> bool { + false + } + fn has_on_off_state(&self) -> bool { + true + } + fn get_reagents(&self) -> Vec<(i32, f64)> { + vec![] + } + fn set_reagents(&mut self, _reagents: &[(i32, f64)]) { + // nope + } + fn add_reagents(&mut self, _reagents: &[(i32, f64)]) { + // nope + } + fn connection_list(&self) -> &[crate::network::Connection] { + &self.connections + } + fn connection_list_mut(&mut self) -> &mut [crate::network::Connection] { + &mut self.connections + } + fn device_pins(&self) -> Option<&[Option]> { + Some(&self.pins) + } + fn device_pins_mut(&mut self) -> Option<&mut [Option]> { + Some(&mut self.pins) + } + fn can_slot_logic_write(&self, _slt: LogicSlotType, _index: f64) -> bool { + false + } + fn set_slot_logic( + &mut self, + slt: LogicSlotType, + index: f64, + _value: f64, + _force: bool, + ) -> Result<(), LogicError> { + Err(LogicError::CantSlotWrite(slt, index)) + } +} + +impl CircuitHolder for StructureCircuitHousing { + fn clear_error(&mut self) { + self.error = 0 + } + fn set_error(&mut self, state: i32) { + self.error = state; + } + /// i32::MAX is db + fn get_logicable_from_index( + &self, + device: i32, + connection: Option, + ) -> Option { + if device == i32::MAX { + // self + if let Some(connection) = connection { + self.connections.get(connection).and_then(|conn| { + if let Connection::CableNetwork { net: Some(net), .. } = conn { + self.vm + .get_network(*net) + .map(ObjectRef::from_vm_object) + } else { + None + } + }) + } else { + Some(ObjectRef::from_ref(self.as_object())) + } + } else { + if device < 0 { + return None; + } + self.pins.get(device as usize).and_then(|pin| { + pin.and_then(|id| { + self.vm + .get_object(id).map(ObjectRef::from_vm_object) + }) + }) + } + } + /// i32::MAX is db + fn get_logicable_from_index_mut( + &mut self, + device: i32, + connection: Option, + ) -> Option { + if device == i32::MAX { + // self + if let Some(connection) = connection { + self.connections.get(connection).and_then(|conn| { + if let Connection::CableNetwork { net: Some(net), .. } = conn { + self.vm + .get_network(*net) + .map(ObjectRefMut::from_vm_object) + } else { + None + } + }) + } else { + Some(ObjectRefMut::from_ref(self.as_mut_object())) + } + } else { + if device < 0 { + return None; + } + self.pins.get(device as usize).and_then(|pin| { + pin.and_then(|id| { + self.vm + .get_object(id).map(ObjectRefMut::from_vm_object) + }) + }) + } + } + + fn get_logicable_from_id( + &self, + device: ObjectID, + connection: Option, + ) -> Option { + if connection.is_some() { + return None; // this functionality is disabled in the game, no network access via ReferenceId + } + if device == self.id { + return Some(ObjectRef::from_ref(self.as_object())); + } + self.vm + .get_object(device).map(ObjectRef::from_vm_object) + } + + fn get_logicable_from_id_mut( + &mut self, + device: ObjectID, + connection: Option, + ) -> Option { + if connection.is_some() { + return None; // this functionality is disabled in the game, no network access via ReferenceId + } + if device == self.id { + return Some(ObjectRefMut::from_ref(self.as_mut_object())); + } + self.vm + .get_object(device).map(ObjectRefMut::from_vm_object) + } + + fn get_ic(&self) -> Option { + self.slot.occupant.and_then(|id| self.vm.get_object(id)) + } + + fn get_ic_mut(&self) -> Option { + self.slot.occupant.and_then(|id| self.vm.get_object(id)) + } + + fn hault_and_catch_fire(&mut self) { + // TODO: do something here?? + } +} diff --git a/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs b/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs index 96f2d02..2edb817 100644 --- a/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs +++ b/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs @@ -97,11 +97,11 @@ impl Storage for ItemIntegratedCircuit10 { fn get_slot_mut(&mut self, _index: usize) -> Option<&mut Slot> { None } - fn get_slots(&self) -> &[Slot] { - &[] + fn get_slots(&self) -> Vec<&Slot> { + vec![] } - fn get_slots_mut(&mut self) -> &mut [Slot] { - &mut [] + fn get_slots_mut(&mut self) -> Vec<&mut Slot> { + vec![] } } @@ -165,11 +165,11 @@ impl Logicable for ItemIntegratedCircuit10 { _ => Err(LogicError::CantWrite(lt)), }) } - fn can_slot_logic_read(&self, _slt: LogicSlotType,_indexx: f64) -> bool { + fn can_slot_logic_read(&self, _slt: LogicSlotType, _indexx: f64) -> bool { false } fn get_slot_logic(&self, _slt: LogicSlotType, index: f64) -> Result { - return Err(LogicError::SlotIndexOutOfRange(index, self.slots_count())); + Err(LogicError::SlotIndexOutOfRange(index, self.slots_count())) } fn valid_logic_types(&self) -> Vec { self.fields.keys().copied().collect() @@ -235,8 +235,7 @@ impl SourceCode for ItemIntegratedCircuit10 { impl IntegratedCircuit for ItemIntegratedCircuit10 { fn get_circuit_holder(&self) -> Option { self.get_parent_slot() - .map(|parent_slot| self.get_vm().get_object(parent_slot.parent)) - .flatten() + .and_then(|parent_slot| self.get_vm().get_object(parent_slot.parent)) } fn get_instruction_pointer(&self) -> f64 { self.ip as f64 @@ -371,7 +370,7 @@ impl IC10Marker for ItemIntegratedCircuit10 {} impl Programmable for ItemIntegratedCircuit10 { fn step(&mut self, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError> { - if matches!(&self.state, ICState::HasCaughtFire ) { + if matches!(&self.state, ICState::HasCaughtFire) { return Ok(()); } if matches!(&self.state, ICState::Error(_)) && !advance_ip_on_err { @@ -394,7 +393,7 @@ impl Programmable for ItemIntegratedCircuit10 { return Err(ICError::SleepDurationError(*sleep_for)); } } - if self.ip >= self.program.len() || self.program.len() == 0 { + if self.ip >= self.program.len() || self.program.is_empty() { self.state = ICState::Ended; return Ok(()); } @@ -403,17 +402,34 @@ impl Programmable for ItemIntegratedCircuit10 { let line = self.program.get_line(self.ip)?.clone(); let operands = &line.operands; let instruction = line.instruction; - instruction.execute(self, operands)?; - self.ip = self.next_ip; - if self.ip >= self.program.len() { - self.state = ICState::Ended; + let result = instruction.execute(self, operands); + + let was_error = if let Err(_err) = result { + self.get_circuit_holder() + .ok_or(ICError::NoCircuitHolder(self.id))? + .borrow_mut() + .as_mut_circuit_holder() + .ok_or(ICError::CircuitHolderNotLogicable(self.id))? + .set_error(1); + true + } else { + false + }; + + if !was_error || advance_ip_on_err { + self.ip = self.next_ip; + if self.ip >= self.program.len() { + self.state = ICState::Ended; + } } + self.get_circuit_holder() .ok_or(ICError::NoCircuitHolder(self.id))? .borrow_mut() .as_mut_logicable() .ok_or(ICError::CircuitHolderNotLogicable(self.id))? .set_logic(LogicType::LineNumber, self.ip as f64, true)?; + Ok(()) } } diff --git a/ic10emu/src/vm/object/templates.rs b/ic10emu/src/vm/object/templates.rs index 88052d5..613c96f 100644 --- a/ic10emu/src/vm/object/templates.rs +++ b/ic10emu/src/vm/object/templates.rs @@ -1167,7 +1167,7 @@ impl ObjectTemplate { logic: logic.into(), memory: mem_r.into(), })), - _ => Err(TemplateError::NonConformingObject(obj_ref.get_id())), + _ => Err(TemplateError::NonConformingObject(*obj_ref.get_id())), } } } @@ -1243,7 +1243,7 @@ impl From<&VMObject> for ObjectInfo { let obj_ref = obj.borrow(); ObjectInfo { name: Some(obj_ref.get_name().value.clone()), - id: Some(obj_ref.get_id()), + id: Some(*obj_ref.get_id()), } } } diff --git a/ic10emu/src/vm/object/traits.rs b/ic10emu/src/vm/object/traits.rs index a85703d..75c98fb 100644 --- a/ic10emu/src/vm/object/traits.rs +++ b/ic10emu/src/vm/object/traits.rs @@ -22,7 +22,6 @@ pub struct ParentSlotInfo { pub parent: ObjectID, pub slot: usize, } - tag_object_traits! { #![object_trait(Object: Debug)] @@ -34,8 +33,8 @@ tag_object_traits! { fn slots_count(&self) -> usize; fn get_slot(&self, index: usize) -> Option<&Slot>; fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot>; - fn get_slots(&self) -> &[Slot]; - fn get_slots_mut(&mut self) -> &mut [Slot]; + fn get_slots(&self) -> Vec<&Slot>; + fn get_slots_mut(&mut self) -> Vec<&mut Slot>; } pub trait MemoryReadable { @@ -80,16 +79,25 @@ tag_object_traits! { &self, device: i32, connection: Option, - ) -> Option; + ) -> Option; /// i32::MAX is db + fn get_logicable_from_index_mut( + &mut self, + device: i32, + connection: Option, + ) -> Option; fn get_logicable_from_id( &self, device: ObjectID, connection: Option, - ) -> Option; - fn get_source_code(&self) -> String; - fn set_source_code(&self, code: String); - fn get_ic(&self) -> Option; + ) -> Option; + fn get_logicable_from_id_mut( + &mut self, + device: ObjectID, + connection: Option, + ) -> Option; + fn get_ic(&self) -> Option; + fn get_ic_mut(&self) -> Option; fn hault_and_catch_fire(&mut self); }