refactor(vm): impl circuit holder, impl ObjectRef/Mut

This commit is contained in:
Rachel Powers
2024-05-18 04:11:38 -07:00
parent cc6cc355dc
commit 29ef54ca04
11 changed files with 952 additions and 344 deletions

View File

@@ -77,6 +77,11 @@ impl Program {
self.instructions.len() self.instructions.len()
} }
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn try_from_code(code: &str) -> Result<Self, ICError> { pub fn try_from_code(code: &str) -> Result<Self, ICError> {
let parse_tree = grammar::parse(code)?; let parse_tree = grammar::parse(code)?;
let mut labels_set = HashSet::new(); let mut labels_set = HashSet::new();

View File

@@ -865,10 +865,10 @@ impl<T: IC10Marker> BdseInstruction for T {
let a = a.as_value(self)?; let a = a.as_value(self)?;
if self if self
.get_circuit_holder() .get_circuit_holder()
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.borrow() .borrow()
.as_circuit_holder() .as_circuit_holder()
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.get_logicable_from_index(device, connection) .get_logicable_from_index(device, connection)
.is_some() .is_some()
{ {
@@ -885,10 +885,10 @@ impl<T: IC10Marker> BdsealInstruction for T {
let a = a.as_value(self)?; let a = a.as_value(self)?;
if self if self
.get_circuit_holder() .get_circuit_holder()
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.borrow() .borrow()
.as_circuit_holder() .as_circuit_holder()
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.get_logicable_from_index(device, connection) .get_logicable_from_index(device, connection)
.is_some() .is_some()
{ {
@@ -906,10 +906,10 @@ impl<T: IC10Marker> BrdseInstruction for T {
let a = a.as_value(self)?; let a = a.as_value(self)?;
if self if self
.get_circuit_holder() .get_circuit_holder()
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.borrow() .borrow()
.as_circuit_holder() .as_circuit_holder()
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.get_logicable_from_index(device, connection) .get_logicable_from_index(device, connection)
.is_some() .is_some()
{ {
@@ -926,10 +926,10 @@ impl<T: IC10Marker> BdnsInstruction for T {
let a = a.as_value(self)?; let a = a.as_value(self)?;
if self if self
.get_circuit_holder() .get_circuit_holder()
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.borrow() .borrow()
.as_circuit_holder() .as_circuit_holder()
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.get_logicable_from_index(device, connection) .get_logicable_from_index(device, connection)
.is_none() .is_none()
{ {
@@ -946,10 +946,10 @@ impl<T: IC10Marker> BdnsalInstruction for T {
let a = a.as_value(self)?; let a = a.as_value(self)?;
if self if self
.get_circuit_holder() .get_circuit_holder()
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.borrow() .borrow()
.as_circuit_holder() .as_circuit_holder()
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.get_logicable_from_index(device, connection) .get_logicable_from_index(device, connection)
.is_none() .is_none()
{ {
@@ -967,10 +967,10 @@ impl<T: IC10Marker> BrdnsInstruction for T {
let a = a.as_value(self)?; let a = a.as_value(self)?;
if self if self
.get_circuit_holder() .get_circuit_holder()
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.borrow() .borrow()
.as_circuit_holder() .as_circuit_holder()
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.get_logicable_from_index(device, connection) .get_logicable_from_index(device, connection)
.is_none() .is_none()
{ {
@@ -1341,14 +1341,16 @@ impl<T: IC10Marker> SdseInstruction for T {
target, target,
} = r.as_register(self)?; } = r.as_register(self)?;
let (device, connection) = d.as_device(self)?; let (device, connection) = d.as_device(self)?;
let obj = self let is_some = {
.get_circuit_holder() self.get_circuit_holder()
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.borrow() .borrow()
.as_circuit_holder() .as_circuit_holder()
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.get_logicable_from_index(device, connection); .get_logicable_from_index(device, connection)
self.set_register(indirection, target, if obj.is_some() { 1.0 } else { 0.0 })?; .is_some()
};
self.set_register(indirection, target, if is_some { 1.0 } else { 0.0 })?;
Ok(()) Ok(())
} }
} }
@@ -1360,14 +1362,16 @@ impl<T: IC10Marker> SdnsInstruction for T {
target, target,
} = r.as_register(self)?; } = r.as_register(self)?;
let (device, connection) = d.as_device(self)?; let (device, connection) = d.as_device(self)?;
let obj = self let is_none = {
.get_circuit_holder() self.get_circuit_holder()
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.borrow() .borrow()
.as_circuit_holder() .as_circuit_holder()
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.get_logicable_from_index(device, connection); .get_logicable_from_index(device, connection)
self.set_register(indirection, target, if obj.is_none() { 1.0 } else { 0.0 })?; .is_none()
};
self.set_register(indirection, target, if is_none { 1.0 } else { 0.0 })?;
Ok(()) Ok(())
} }
} }
@@ -1988,19 +1992,22 @@ impl<T: IC10Marker> GetInstruction for T {
} = r.as_register(self)?; } = r.as_register(self)?;
let address = address.as_value(self)?; let address = address.as_value(self)?;
let (device, connection) = d.as_device(self)?; let (device, connection) = d.as_device(self)?;
let obj = self self.get_circuit_holder()
.get_circuit_holder() .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
.borrow() .borrow()
.as_circuit_holder() .as_circuit_holder()
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.get_logicable_from_index(device, connection) .get_logicable_from_index(device, connection)
.ok_or(ICError::DeviceNotSet)?; .ok_or(ICError::DeviceNotSet)
let obj_ref = obj.borrow(); .and_then(|obj| {
let memory = obj_ref obj.map(|obj_ref| {
.as_memory_readable() let val = obj_ref
.ok_or(MemoryError::NotReadable)?; .as_memory_readable()
self.set_register(indirection, target, memory.get_memory(address as i32)?)?; .ok_or(MemoryError::NotWriteable)?
.get_memory(address as i32)?;
self.set_register(indirection, target, val)
})
})?;
Ok(()) Ok(())
} }
} }
@@ -2019,19 +2026,22 @@ impl<T: IC10Marker> GetdInstruction for T {
} = r.as_register(self)?; } = r.as_register(self)?;
let id = id.as_value(self)?; let id = id.as_value(self)?;
let address = address.as_value(self)?; let address = address.as_value(self)?;
let obj = self self.get_circuit_holder()
.get_circuit_holder() .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
.borrow() .borrow()
.as_circuit_holder() .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) .get_logicable_from_id(id as ObjectID, None)
.ok_or(ICError::DeviceNotSet)?; .ok_or(ICError::DeviceNotSet)
let obj_ref = obj.borrow(); .and_then(|obj| {
let memory = obj_ref obj.map(|obj_ref| {
.as_memory_readable() let val = obj_ref
.ok_or(MemoryError::NotReadable)?; .as_memory_readable()
self.set_register(indirection, target, memory.get_memory(address as i32)?)?; .ok_or(MemoryError::NotWriteable)?
.get_memory(address as i32)?;
self.set_register(indirection, target, val)
})
})?;
Ok(()) Ok(())
} }
} }
@@ -2047,19 +2057,22 @@ impl<T: IC10Marker> PutInstruction for T {
let (device, connection) = d.as_device(self)?; let (device, connection) = d.as_device(self)?;
let address = address.as_value(self)?; let address = address.as_value(self)?;
let value = value.as_value(self)?; let value = value.as_value(self)?;
let obj = self self.get_circuit_holder()
.get_circuit_holder() .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .borrow_mut()
.borrow() .as_mut_circuit_holder()
.as_circuit_holder() .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .get_logicable_from_index_mut(device, connection)
.get_logicable_from_index(device, connection) .ok_or(ICError::DeviceNotSet)
.ok_or(ICError::DeviceNotSet)?; .and_then(|mut obj| {
let mut obj_ref = obj.borrow_mut(); obj.map(|obj_ref| {
let memory = obj_ref obj_ref
.as_mut_memory_writable() .as_mut_memory_writable()
.ok_or(MemoryError::NotWriteable)?; .ok_or(MemoryError::NotWriteable)?
memory.set_memory(address as i32, value)?; .set_memory(address as i32, value)
.map_err(Into::into)
})
})?;
Ok(()) Ok(())
} }
} }
@@ -2075,19 +2088,22 @@ impl<T: IC10Marker> PutdInstruction for T {
let id = id.as_value(self)?; let id = id.as_value(self)?;
let address = address.as_value(self)?; let address = address.as_value(self)?;
let value = value.as_value(self)?; let value = value.as_value(self)?;
let obj = self self.get_circuit_holder()
.get_circuit_holder() .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .borrow_mut()
.borrow() .as_mut_circuit_holder()
.as_circuit_holder() .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .get_logicable_from_id_mut(id as ObjectID, None)
.get_logicable_from_id(id as ObjectID, None) .ok_or(ICError::DeviceNotSet)
.ok_or(ICError::DeviceNotSet)?; .and_then(|mut obj| {
let mut obj_ref = obj.borrow_mut(); obj.map(|obj_ref| {
let memory = obj_ref obj_ref
.as_mut_memory_writable() .as_mut_memory_writable()
.ok_or(MemoryError::NotWriteable)?; .ok_or(MemoryError::NotWriteable)?
memory.set_memory(address as i32, value)?; .set_memory(address as i32, value)
.map_err(Into::into)
})
})?;
Ok(()) Ok(())
} }
} }
@@ -2096,19 +2112,22 @@ impl<T: IC10Marker> ClrInstruction for T {
/// clr d? /// clr d?
fn execute_inner(&mut self, d: &InstOperand) -> Result<(), ICError> { fn execute_inner(&mut self, d: &InstOperand) -> Result<(), ICError> {
let (device, connection) = d.as_device(self)?; let (device, connection) = d.as_device(self)?;
let obj = self self.get_circuit_holder()
.get_circuit_holder() .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .borrow_mut()
.borrow() .as_mut_circuit_holder()
.as_circuit_holder() .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .get_logicable_from_index_mut(device, connection)
.get_logicable_from_index(device, connection) .ok_or(ICError::DeviceNotSet)
.ok_or(ICError::DeviceNotSet)?; .and_then(|mut obj| {
let mut obj_ref = obj.borrow_mut(); obj.map(|obj_ref| {
let memory = obj_ref obj_ref
.as_mut_memory_writable() .as_mut_memory_writable()
.ok_or(MemoryError::NotWriteable)?; .ok_or(MemoryError::NotWriteable)?
memory.clear_memory()?; .clear_memory()
.map_err(Into::into)
})
})?;
Ok(()) Ok(())
} }
} }
@@ -2116,19 +2135,22 @@ impl<T: IC10Marker> ClrdInstruction for T {
/// clrd id(r?|num) /// clrd id(r?|num)
fn execute_inner(&mut self, id: &InstOperand) -> Result<(), ICError> { fn execute_inner(&mut self, id: &InstOperand) -> Result<(), ICError> {
let id = id.as_value(self)?; let id = id.as_value(self)?;
let obj = self self.get_circuit_holder()
.get_circuit_holder() .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .borrow_mut()
.borrow() .as_mut_circuit_holder()
.as_circuit_holder() .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .get_logicable_from_id_mut(id as ObjectID, None)
.get_logicable_from_id(id as ObjectID, None) .ok_or(ICError::DeviceNotSet)
.ok_or(ICError::DeviceNotSet)?; .and_then(|mut obj| {
let mut obj_ref = obj.borrow_mut(); obj.map(|obj_ref| {
let memory = obj_ref obj_ref
.as_mut_memory_writable() .as_mut_memory_writable()
.ok_or(MemoryError::NotWriteable)?; .ok_or(MemoryError::NotWriteable)?
memory.clear_memory()?; .clear_memory()
.map_err(Into::into)
})
})?;
Ok(()) Ok(())
} }
} }
@@ -2144,23 +2166,30 @@ impl<T: IC10Marker> SInstruction for T {
let (device, connection) = d.as_device(self)?; let (device, connection) = d.as_device(self)?;
let logic_type = logic_type.as_logic_type(self)?; let logic_type = logic_type.as_logic_type(self)?;
let val = r.as_value(self)?; let val = r.as_value(self)?;
let obj = self self.get_circuit_holder()
.get_circuit_holder() .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .borrow_mut()
.borrow() .as_mut_circuit_holder()
.as_circuit_holder() .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .get_logicable_from_index_mut(device, connection)
.get_logicable_from_index(device, connection) .ok_or(ICError::DeviceNotSet)
.ok_or(ICError::DeviceNotSet)?; .and_then(|mut obj| {
let mut obj_ref = obj.borrow_mut(); let obj_id = obj.get_id();
let device_id = obj_ref.get_id(); obj.map(|obj_ref| {
let logicable = obj_ref obj_ref
.as_mut_logicable() .as_mut_logicable()
.ok_or(ICError::NotLogicable(device_id))?; .ok_or(ICError::NotLogicable(obj_id))
if !logicable.can_logic_write(logic_type) { .and_then(|logicable| {
return Err(LogicError::CantWrite(logic_type).into()); if !logicable.can_logic_write(logic_type) {
} Err(LogicError::CantWrite(logic_type).into())
logicable.set_logic(logic_type, val, false)?; } else {
logicable
.set_logic(logic_type, val, false)
.map_err(Into::into)
}
})
})
})?;
Ok(()) Ok(())
} }
} }
@@ -2176,23 +2205,30 @@ impl<T: IC10Marker> SdInstruction for T {
let id = id.as_value(self)?; let id = id.as_value(self)?;
let logic_type = logic_type.as_logic_type(self)?; let logic_type = logic_type.as_logic_type(self)?;
let val = r.as_value(self)?; let val = r.as_value(self)?;
let obj = self self.get_circuit_holder()
.get_circuit_holder() .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .borrow_mut()
.borrow() .as_mut_circuit_holder()
.as_circuit_holder() .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .get_logicable_from_id_mut(id as ObjectID, None)
.get_logicable_from_id(id as ObjectID, None) .ok_or(ICError::DeviceNotSet)
.ok_or(ICError::DeviceNotSet)?; .and_then(|mut obj| {
let mut obj_ref = obj.borrow_mut(); let obj_id = obj.get_id();
let device_id = obj_ref.get_id(); obj.map(|obj_ref| {
let logicable = obj_ref obj_ref
.as_mut_logicable() .as_mut_logicable()
.ok_or(ICError::NotLogicable(device_id))?; .ok_or(ICError::NotLogicable(obj_id))
if !logicable.can_logic_write(logic_type) { .and_then(|logicable| {
return Err(LogicError::CantWrite(logic_type).into()); if !logicable.can_logic_write(logic_type) {
} Err(LogicError::CantWrite(logic_type).into())
logicable.set_logic(logic_type, val, false)?; } else {
logicable
.set_logic(logic_type, val, false)
.map_err(Into::into)
}
})
})
})?;
Ok(()) Ok(())
} }
} }
@@ -2210,27 +2246,30 @@ impl<T: IC10Marker> SsInstruction for T {
let slot_index = slot_index.as_value(self)?; let slot_index = slot_index.as_value(self)?;
let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?;
let val = r.as_value(self)?; let val = r.as_value(self)?;
let obj = self self.get_circuit_holder()
.get_circuit_holder() .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .borrow_mut()
.borrow() .as_mut_circuit_holder()
.as_circuit_holder() .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .get_logicable_from_index_mut(device, connection)
.get_logicable_from_index(device, connection) .ok_or(ICError::DeviceNotSet)
.ok_or(ICError::DeviceNotSet)?; .and_then(|mut obj| {
let mut obj_ref = obj.borrow_mut(); let obj_id = obj.get_id();
let device_id = obj_ref.get_id(); obj.map(|obj_ref| {
let logicable = obj_ref obj_ref
.as_mut_logicable() .as_mut_device()
.ok_or(ICError::NotLogicable(device_id))?; .ok_or(ICError::NotLogicable(obj_id))
let device_id = logicable.get_id(); .and_then(|logicable| {
let device = logicable if !logicable.can_slot_logic_write(logic_slot_type, slot_index) {
.as_mut_device() Err(LogicError::CantSlotWrite(logic_slot_type, slot_index).into())
.ok_or(ICError::NotSlotWriteable(device_id))?; } else {
if !device.can_slot_logic_write(logic_slot_type, slot_index) { logicable
return Err(LogicError::CantSlotWrite(logic_slot_type, slot_index).into()); .set_slot_logic(logic_slot_type, slot_index, val, false)
} .map_err(Into::into)
device.set_slot_logic(logic_slot_type, slot_index, val, false)?; }
})
})
})?;
Ok(()) Ok(())
} }
} }
@@ -2248,7 +2287,7 @@ impl<T: IC10Marker> SbInstruction for T {
let logic_type = logic_type.as_logic_type(self)?; let logic_type = logic_type.as_logic_type(self)?;
let val = r.as_value(self)?; let val = r.as_value(self)?;
self.get_vm() 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(()) Ok(())
} }
} }
@@ -2268,7 +2307,7 @@ impl<T: IC10Marker> SbsInstruction for T {
let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?;
let val = r.as_value(self)?; let val = r.as_value(self)?;
self.get_vm().set_batch_device_slot_field( self.get_vm().set_batch_device_slot_field(
self.get_id(), *self.get_id(),
prefab, prefab,
slot_index, slot_index,
logic_slot_type, logic_slot_type,
@@ -2294,7 +2333,7 @@ impl<T: IC10Marker> SbnInstruction for T {
let logic_type = logic_type.as_logic_type(self)?; let logic_type = logic_type.as_logic_type(self)?;
let val = r.as_value(self)?; let val = r.as_value(self)?;
self.get_vm().set_batch_name_device_field( self.get_vm().set_batch_name_device_field(
self.get_id(), *self.get_id(),
prefab, prefab,
name, name,
logic_type, logic_type,
@@ -2320,22 +2359,29 @@ impl<T: IC10Marker> LInstruction for T {
} = r.as_register(self)?; } = r.as_register(self)?;
let (device, connection) = d.as_device(self)?; let (device, connection) = d.as_device(self)?;
let logic_type = logic_type.as_logic_type(self)?; let logic_type = logic_type.as_logic_type(self)?;
let obj = self let val = self
.get_circuit_holder() .get_circuit_holder()
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.borrow() .borrow()
.as_circuit_holder() .as_circuit_holder()
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.get_logicable_from_index(device, connection) .get_logicable_from_index(device, connection)
.ok_or(ICError::DeviceNotSet)?; .ok_or(ICError::DeviceNotSet)
let obj_ref = obj.borrow(); .and_then(|obj| {
let logicable = obj_ref obj.map(|obj_ref| {
.as_logicable() obj_ref
.ok_or(ICError::NotLogicable(obj_ref.get_id()))?; .as_logicable()
if !logicable.can_logic_read(logic_type) { .ok_or(ICError::NotLogicable(*obj_ref.get_id()))
return Err(LogicError::CantRead(logic_type).into()); .and_then(|logicable| {
} if !logicable.can_logic_read(logic_type) {
self.set_register(indirection, target, logicable.get_logic(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(()) Ok(())
} }
} }
@@ -2354,22 +2400,29 @@ impl<T: IC10Marker> LdInstruction for T {
} = r.as_register(self)?; } = r.as_register(self)?;
let id = id.as_value(self)?; let id = id.as_value(self)?;
let logic_type = logic_type.as_logic_type(self)?; let logic_type = logic_type.as_logic_type(self)?;
let obj = self let val = self
.get_circuit_holder() .get_circuit_holder()
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.borrow() .borrow()
.as_circuit_holder() .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) .get_logicable_from_id(id as ObjectID, None)
.ok_or(ICError::DeviceNotSet)?; .ok_or(ICError::DeviceNotSet)
let obj_ref = obj.borrow(); .and_then(|obj| {
let logicable = obj_ref obj.map(|obj_ref| {
.as_logicable() obj_ref
.ok_or(ICError::NotLogicable(obj_ref.get_id()))?; .as_logicable()
if !logicable.can_logic_read(logic_type) { .ok_or(ICError::NotLogicable(*obj_ref.get_id()))
return Err(LogicError::CantRead(logic_type).into()); .and_then(|logicable| {
} if !logicable.can_logic_read(logic_type) {
self.set_register(indirection, target, logicable.get_logic(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(()) Ok(())
} }
} }
@@ -2390,26 +2443,31 @@ impl<T: IC10Marker> LsInstruction for T {
let (device, connection) = d.as_device(self)?; let (device, connection) = d.as_device(self)?;
let slot_index = slot_index.as_value(self)?; let slot_index = slot_index.as_value(self)?;
let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?;
let obj = self let val = self
.get_circuit_holder() .get_circuit_holder()
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.borrow() .borrow()
.as_circuit_holder() .as_circuit_holder()
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.get_logicable_from_index(device, connection) .get_logicable_from_index(device, connection)
.ok_or(ICError::DeviceNotSet)?; .ok_or(ICError::DeviceNotSet)
let obj_ref = obj.borrow(); .and_then(|obj| {
let logicable = obj_ref obj.map(|obj_ref| {
.as_logicable() obj_ref
.ok_or(ICError::NotLogicable(obj_ref.get_id()))?; .as_logicable()
if !logicable.can_slot_logic_read(logic_slot_type, slot_index) { .ok_or(ICError::NotLogicable(*obj_ref.get_id()))
return Err(LogicError::CantSlotRead(logic_slot_type, slot_index).into()); .and_then(|logicable| {
} if !logicable.can_slot_logic_read(logic_slot_type, slot_index) {
self.set_register( Err(LogicError::CantSlotRead(logic_slot_type, slot_index).into())
indirection, } else {
target, logicable
logicable.get_slot_logic(logic_slot_type, slot_index)?, .get_slot_logic(logic_slot_type, slot_index)
)?; .map_err(Into::into)
}
})
})
})?;
self.set_register(indirection, target, val)?;
Ok(()) Ok(())
} }
} }
@@ -2430,66 +2488,70 @@ impl<T: IC10Marker> LrInstruction for T {
let (device, connection) = d.as_device(self)?; let (device, connection) = d.as_device(self)?;
let reagent_mode = reagent_mode.as_reagent_mode(self)?; let reagent_mode = reagent_mode.as_reagent_mode(self)?;
let int = int.as_value(self)?; let int = int.as_value(self)?;
let obj = self let val = self
.get_circuit_holder() .get_circuit_holder()
.ok_or(ICError::NoCircuitHolder(self.get_id()))? .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.borrow() .borrow()
.as_circuit_holder() .as_circuit_holder()
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.get_logicable_from_index(device, connection) .get_logicable_from_index(device, connection)
.ok_or(ICError::DeviceNotSet)?; .ok_or(ICError::DeviceNotSet)
let obj_ref = obj.borrow(); .and_then(|obj| {
let logicable = obj_ref obj.map(|obj_ref| {
.as_logicable() obj_ref
.ok_or(ICError::NotLogicable(obj_ref.get_id()))?; .as_logicable()
.ok_or(ICError::NotLogicable(*obj_ref.get_id()))
let result = match reagent_mode { .and_then(|logicable| {
LogicReagentMode::Contents => { let result = match reagent_mode {
let device = logicable LogicReagentMode::Contents => {
.as_device() let device = logicable
.ok_or(ICError::NotReagentReadable(logicable.get_id()))?; .as_device()
device .ok_or(ICError::NotReagentReadable(*logicable.get_id()))?;
.get_reagents() device
.iter() .get_reagents()
.find(|(hash, _)| *hash as f64 == int) .iter()
.map(|(_, quantity)| *quantity) .find(|(hash, _)| *hash as f64 == int)
.unwrap_or(0.0) .map(|(_, quantity)| *quantity)
} .unwrap_or(0.0)
LogicReagentMode::TotalContents => { }
let device = logicable LogicReagentMode::TotalContents => {
.as_device() let device = logicable
.ok_or(ICError::NotReagentReadable(logicable.get_id()))?; .as_device()
device .ok_or(ICError::NotReagentReadable(*logicable.get_id()))?;
.get_reagents() device
.iter() .get_reagents()
.map(|(_, quantity)| quantity) .iter()
.sum() .map(|(_, quantity)| quantity)
} .sum()
LogicReagentMode::Required => { }
let reagent_interface = logicable LogicReagentMode::Required => {
.as_reagent_interface() let reagent_interface = logicable
.ok_or(ICError::NotReagentReadable(logicable.get_id()))?; .as_reagent_interface()
reagent_interface .ok_or(ICError::NotReagentReadable(*logicable.get_id()))?;
.get_current_required() reagent_interface
.iter() .get_current_required()
.find(|(hash, _)| *hash as f64 == int) .iter()
.map(|(_, quantity)| *quantity) .find(|(hash, _)| *hash as f64 == int)
.unwrap_or(0.0) .map(|(_, quantity)| *quantity)
} .unwrap_or(0.0)
LogicReagentMode::Recipe => { }
let reagent_interface = logicable LogicReagentMode::Recipe => {
.as_reagent_interface() let reagent_interface = logicable
.ok_or(ICError::NotReagentReadable(logicable.get_id()))?; .as_reagent_interface()
reagent_interface .ok_or(ICError::NotReagentReadable(*logicable.get_id()))?;
.get_current_recipie() reagent_interface
.iter() .get_current_recipie()
.find(|(hash, _)| *hash as f64 == int) .iter()
.map(|(_, quantity)| *quantity) .find(|(hash, _)| *hash as f64 == int)
.unwrap_or(0.0) .map(|(_, quantity)| *quantity)
} .unwrap_or(0.0)
}; }
};
self.set_register(indirection, target, result)?; Ok(result)
})
})
})?;
self.set_register(indirection, target, val)?;
Ok(()) Ok(())
} }
} }
@@ -2513,7 +2575,7 @@ impl<T: IC10Marker> LbInstruction for T {
let batch_mode = batch_mode.as_batch_mode(self)?; let batch_mode = batch_mode.as_batch_mode(self)?;
let val = let val =
self.get_vm() 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)?; self.set_register(indirection, target, val)?;
Ok(()) Ok(())
} }
@@ -2539,7 +2601,7 @@ impl<T: IC10Marker> LbnInstruction for T {
let logic_type = logic_type.as_logic_type(self)?; let logic_type = logic_type.as_logic_type(self)?;
let batch_mode = batch_mode.as_batch_mode(self)?; let batch_mode = batch_mode.as_batch_mode(self)?;
let val = self.get_vm().get_batch_name_device_field( let val = self.get_vm().get_batch_name_device_field(
self.get_id(), *self.get_id(),
prefab, prefab,
name, name,
logic_type, logic_type,
@@ -2572,7 +2634,7 @@ impl<T: IC10Marker> LbnsInstruction for T {
let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?;
let batch_mode = batch_mode.as_batch_mode(self)?; let batch_mode = batch_mode.as_batch_mode(self)?;
let val = self.get_vm().get_batch_name_device_slot_field( let val = self.get_vm().get_batch_name_device_slot_field(
self.get_id(), *self.get_id(),
prefab, prefab,
name, name,
slot_index, slot_index,
@@ -2604,7 +2666,7 @@ impl<T: IC10Marker> LbsInstruction for T {
let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?; let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?;
let batch_mode = batch_mode.as_batch_mode(self)?; let batch_mode = batch_mode.as_batch_mode(self)?;
let val = self.get_vm().get_batch_device_slot_field( let val = self.get_vm().get_batch_device_slot_field(
self.get_id(), *self.get_id(),
prefab, prefab,
slot_index, slot_index,
logic_slot_type, logic_slot_type,
@@ -2618,12 +2680,14 @@ impl<T: IC10Marker> LbsInstruction for T {
impl<T: IC10Marker> HcfInstruction for T { impl<T: IC10Marker> HcfInstruction for T {
/// hcf /// hcf
fn execute_inner(&mut self) -> Result<(), ICError> { fn execute_inner(&mut self) -> Result<(), ICError> {
self.get_circuit_holder() {
.ok_or(ICError::NoCircuitHolder(self.get_id()))? self.get_circuit_holder()
.borrow_mut() .ok_or(ICError::NoCircuitHolder(*self.get_id()))?
.as_mut_circuit_holder() .borrow_mut()
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))? .as_mut_circuit_holder()
.hault_and_catch_fire(); .ok_or(ICError::CircuitHolderNotLogicable(*self.get_id()))?
.hault_and_catch_fire();
}
self.set_state(ICState::HasCaughtFire); self.set_state(ICState::HasCaughtFire);
Ok(()) Ok(())
} }

View File

@@ -235,11 +235,11 @@ impl Storage for CableNetwork {
fn get_slot_mut(&mut self, _index: usize) -> Option<&mut crate::vm::object::Slot> { fn get_slot_mut(&mut self, _index: usize) -> Option<&mut crate::vm::object::Slot> {
None 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] { fn get_slots_mut(&mut self) -> Vec<&mut crate::vm::object::Slot> {
&mut [] vec![]
} }
} }
@@ -422,7 +422,7 @@ where
impl From<NetworkRef<'_>> for FrozenCableNetwork { impl From<NetworkRef<'_>> for FrozenCableNetwork {
fn from(value: NetworkRef) -> Self { fn from(value: NetworkRef) -> Self {
FrozenCableNetwork { FrozenCableNetwork {
id: value.get_id(), id: *value.get_id(),
devices: value.get_devices(), devices: value.get_devices(),
power_only: value.get_power_only(), power_only: value.get_power_only(),
channels: *value.get_channel_data(), channels: *value.get_channel_data(),

View File

@@ -617,7 +617,7 @@ impl VM {
) -> Result<(), ICError> { ) -> Result<(), ICError> {
self.batch_device(source, prefab, None) self.batch_device(source, prefab, None)
.map(|device| { .map(|device| {
self.set_modified(device.borrow().get_id()); self.set_modified(*device.borrow().get_id());
device device
.borrow_mut() .borrow_mut()
.as_mut_device() .as_mut_device()
@@ -639,7 +639,7 @@ impl VM {
) -> Result<(), ICError> { ) -> Result<(), ICError> {
self.batch_device(source, prefab, None) self.batch_device(source, prefab, None)
.map(|device| { .map(|device| {
self.set_modified(device.borrow().get_id()); self.set_modified(*device.borrow().get_id());
device device
.borrow_mut() .borrow_mut()
.as_mut_device() .as_mut_device()
@@ -661,7 +661,7 @@ impl VM {
) -> Result<(), ICError> { ) -> Result<(), ICError> {
self.batch_device(source, prefab, Some(name)) self.batch_device(source, prefab, Some(name))
.map(|device| { .map(|device| {
self.set_modified(device.borrow().get_id()); self.set_modified(*device.borrow().get_id());
device device
.borrow_mut() .borrow_mut()
.as_mut_device() .as_mut_device()

View File

@@ -41,11 +41,11 @@ impl<T: GWStorage + Object> Storage for T {
fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot> { fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot> {
self.slots_mut().get_mut(index) self.slots_mut().get_mut(index)
} }
fn get_slots(&self) -> &[Slot] { fn get_slots(&self) -> Vec<&Slot> {
self.slots() self.slots().iter().collect()
} }
fn get_slots_mut(&mut self) -> &mut [Slot] { fn get_slots_mut(&mut self) -> Vec<&mut Slot> {
self.slots_mut() self.slots_mut().iter_mut().collect()
} }
} }
@@ -63,57 +63,77 @@ impl<T: GWLogicable + Object> Logicable for T {
self.get_name().hash self.get_name().hash
} }
fn is_logic_readable(&self) -> bool { fn is_logic_readable(&self) -> bool {
LogicType::iter().any(|lt| self.can_logic_read(lt)) true
} }
fn is_logic_writeable(&self) -> bool { fn is_logic_writeable(&self) -> bool {
LogicType::iter().any(|lt| self.can_logic_write(lt)) LogicType::iter().any(|lt| self.can_logic_write(lt))
} }
fn can_logic_read(&self, lt: LogicType) -> bool { fn can_logic_read(&self, lt: LogicType) -> bool {
self.fields() match lt {
.get(&lt) LogicType::PrefabHash | LogicType::NameHash | LogicType::ReferenceId => true,
.map(|field| { _ => self
matches!( .fields()
field.field_type, .get(&lt)
MemoryAccess::Read | MemoryAccess::ReadWrite .map(|field| {
) matches!(
}) field.field_type,
.unwrap_or(false) MemoryAccess::Read | MemoryAccess::ReadWrite
)
})
.unwrap_or(false),
}
} }
fn can_logic_write(&self, lt: LogicType) -> bool { fn can_logic_write(&self, lt: LogicType) -> bool {
self.fields() match lt {
.get(&lt) LogicType::PrefabHash | LogicType::NameHash | LogicType::ReferenceId => false,
.map(|field| { _ => self
matches!( .fields()
field.field_type, .get(&lt)
MemoryAccess::Write | MemoryAccess::ReadWrite .map(|field| {
) matches!(
}) field.field_type,
.unwrap_or(false) MemoryAccess::Write | MemoryAccess::ReadWrite
)
})
.unwrap_or(false),
}
} }
fn get_logic(&self, lt: LogicType) -> Result<f64, LogicError> { fn get_logic(&self, lt: LogicType) -> Result<f64, LogicError> {
self.fields() match lt {
.get(&lt) LogicType::PrefabHash => Ok(self.get_prefab().hash as f64),
.and_then(|field| match field.field_type { LogicType::NameHash => Ok(self.get_name().hash as f64),
MemoryAccess::Read | MemoryAccess::ReadWrite => Some(field.value), LogicType::ReferenceId => Ok(*self.get_id() as f64),
_ => None, _ => self
}) .fields()
.ok_or(LogicError::CantRead(lt)) .get(&lt)
.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> { fn set_logic(&mut self, lt: LogicType, value: f64, force: bool) -> Result<(), LogicError> {
self.fields_mut() match lt {
.get_mut(&lt) LogicType::PrefabHash | LogicType::NameHash | LogicType::ReferenceId => {
.ok_or(LogicError::CantWrite(lt)) Err(LogicError::CantWrite(lt))
.and_then(|field| match field.field_type { }
MemoryAccess::Write | MemoryAccess::ReadWrite => { _ => self
field.value = value; .fields_mut()
Ok(()) .get_mut(&lt)
} .ok_or(LogicError::CantWrite(lt))
_ if force => { .and_then(|field| match field.field_type {
field.value = value; MemoryAccess::Write | MemoryAccess::ReadWrite => {
Ok(()) field.value = value;
} Ok(())
_ => Err(LogicError::CantWrite(lt)), }
}) _ if force => {
field.value = value;
Ok(())
}
_ => Err(LogicError::CantWrite(lt)),
}),
}
} }
fn can_slot_logic_read(&self, slt: LogicSlotType, index: f64) -> bool { fn can_slot_logic_read(&self, slt: LogicSlotType, index: f64) -> bool {
if index < 0.0 { if index < 0.0 {
@@ -200,7 +220,7 @@ impl<T: GWLogicable + Object> Logicable for T {
} }
ReferenceId => { ReferenceId => {
if let Some(occupant) = occupant { if let Some(occupant) = occupant {
Ok(occupant.borrow().get_id() as f64) Ok(*occupant.borrow().get_id() as f64)
} else { } else {
Ok(0.0) Ok(0.0)
} }

View File

@@ -8,7 +8,7 @@ macro_rules! object_trait {
} }
}; };
(@body $trait_name:ident { $($trt:ident),* }; ) => { (@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 set_id(&mut self, id: crate::vm::object::ObjectID);
fn get_prefab(&self) -> &crate::vm::object::Name; fn get_prefab(&self) -> &crate::vm::object::Name;
fn get_mut_prefab(&mut self) -> &mut 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<F, R>(&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<F, R>(&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),*}) => { ( $trait_name:ident $(: $($bound:tt)* )? {$($trt:ident),*}) => {
@@ -95,8 +163,8 @@ macro_rules! ObjectInterface {
} => { } => {
impl $trait_name for $struct { impl $trait_name for $struct {
fn get_id(&self) -> crate::vm::object::ObjectID { fn get_id(&self) -> &crate::vm::object::ObjectID {
self.$id_field &self.$id_field
} }
fn set_id(&mut self, id: crate::vm::object::ObjectID) { fn set_id(&mut self, id: crate::vm::object::ObjectID) {

View File

@@ -1,3 +1,4 @@
mod integrated_circuit; mod integrated_circuit;
mod circuit_holder;
pub use integrated_circuit::ItemIntegratedCircuit10; pub use integrated_circuit::ItemIntegratedCircuit10;

View File

@@ -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<VM>,
pub error: i32,
pub on: bool,
pub setting: f64,
pub slot: Slot,
pub pins: [Option<ObjectID>; 6],
pub connections: [crate::network::Connection; 2],
}
#[allow(dead_code)]
impl StructureCircuitHousing {
pub fn new(id: ObjectID, vm: Rc<VM>) -> 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<f64, LogicError> {
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<f64, LogicError> {
Err(LogicError::SlotIndexOutOfRange(index, self.slots_count()))
}
fn valid_logic_types(&self) -> Vec<LogicType> {
use LogicType::*;
vec![
Error,
LineNumber,
NameHash,
On,
Power,
PrefabHash,
ReferenceId,
RequiredPower,
Setting,
]
}
fn known_modes(&self) -> Option<Vec<(u32, String)>> {
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<ObjectID>]> {
Some(&self.pins)
}
fn device_pins_mut(&mut self) -> Option<&mut [Option<ObjectID>]> {
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<usize>,
) -> Option<ObjectRef> {
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<usize>,
) -> Option<ObjectRefMut> {
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<usize>,
) -> Option<ObjectRef> {
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<usize>,
) -> Option<ObjectRefMut> {
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<VMObject> {
self.slot.occupant.and_then(|id| self.vm.get_object(id))
}
fn get_ic_mut(&self) -> Option<VMObject> {
self.slot.occupant.and_then(|id| self.vm.get_object(id))
}
fn hault_and_catch_fire(&mut self) {
// TODO: do something here??
}
}

View File

@@ -97,11 +97,11 @@ impl Storage for ItemIntegratedCircuit10 {
fn get_slot_mut(&mut self, _index: usize) -> Option<&mut Slot> { fn get_slot_mut(&mut self, _index: usize) -> Option<&mut Slot> {
None None
} }
fn get_slots(&self) -> &[Slot] { fn get_slots(&self) -> Vec<&Slot> {
&[] vec![]
} }
fn get_slots_mut(&mut self) -> &mut [Slot] { fn get_slots_mut(&mut self) -> Vec<&mut Slot> {
&mut [] vec![]
} }
} }
@@ -165,11 +165,11 @@ impl Logicable for ItemIntegratedCircuit10 {
_ => Err(LogicError::CantWrite(lt)), _ => 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 false
} }
fn get_slot_logic(&self, _slt: LogicSlotType, index: f64) -> Result<f64, LogicError> { fn get_slot_logic(&self, _slt: LogicSlotType, index: f64) -> Result<f64, LogicError> {
return Err(LogicError::SlotIndexOutOfRange(index, self.slots_count())); Err(LogicError::SlotIndexOutOfRange(index, self.slots_count()))
} }
fn valid_logic_types(&self) -> Vec<LogicType> { fn valid_logic_types(&self) -> Vec<LogicType> {
self.fields.keys().copied().collect() self.fields.keys().copied().collect()
@@ -235,8 +235,7 @@ impl SourceCode for ItemIntegratedCircuit10 {
impl IntegratedCircuit for ItemIntegratedCircuit10 { impl IntegratedCircuit for ItemIntegratedCircuit10 {
fn get_circuit_holder(&self) -> Option<VMObject> { fn get_circuit_holder(&self) -> Option<VMObject> {
self.get_parent_slot() self.get_parent_slot()
.map(|parent_slot| self.get_vm().get_object(parent_slot.parent)) .and_then(|parent_slot| self.get_vm().get_object(parent_slot.parent))
.flatten()
} }
fn get_instruction_pointer(&self) -> f64 { fn get_instruction_pointer(&self) -> f64 {
self.ip as f64 self.ip as f64
@@ -371,7 +370,7 @@ impl IC10Marker for ItemIntegratedCircuit10 {}
impl Programmable for ItemIntegratedCircuit10 { impl Programmable for ItemIntegratedCircuit10 {
fn step(&mut self, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError> { 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(()); return Ok(());
} }
if matches!(&self.state, ICState::Error(_)) && !advance_ip_on_err { if matches!(&self.state, ICState::Error(_)) && !advance_ip_on_err {
@@ -394,7 +393,7 @@ impl Programmable for ItemIntegratedCircuit10 {
return Err(ICError::SleepDurationError(*sleep_for)); 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; self.state = ICState::Ended;
return Ok(()); return Ok(());
} }
@@ -403,17 +402,34 @@ impl Programmable for ItemIntegratedCircuit10 {
let line = self.program.get_line(self.ip)?.clone(); let line = self.program.get_line(self.ip)?.clone();
let operands = &line.operands; let operands = &line.operands;
let instruction = line.instruction; let instruction = line.instruction;
instruction.execute(self, operands)?; let result = instruction.execute(self, operands);
self.ip = self.next_ip;
if self.ip >= self.program.len() { let was_error = if let Err(_err) = result {
self.state = ICState::Ended; 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() self.get_circuit_holder()
.ok_or(ICError::NoCircuitHolder(self.id))? .ok_or(ICError::NoCircuitHolder(self.id))?
.borrow_mut() .borrow_mut()
.as_mut_logicable() .as_mut_logicable()
.ok_or(ICError::CircuitHolderNotLogicable(self.id))? .ok_or(ICError::CircuitHolderNotLogicable(self.id))?
.set_logic(LogicType::LineNumber, self.ip as f64, true)?; .set_logic(LogicType::LineNumber, self.ip as f64, true)?;
Ok(()) Ok(())
} }
} }

View File

@@ -1167,7 +1167,7 @@ impl ObjectTemplate {
logic: logic.into(), logic: logic.into(),
memory: mem_r.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(); let obj_ref = obj.borrow();
ObjectInfo { ObjectInfo {
name: Some(obj_ref.get_name().value.clone()), name: Some(obj_ref.get_name().value.clone()),
id: Some(obj_ref.get_id()), id: Some(*obj_ref.get_id()),
} }
} }
} }

View File

@@ -22,7 +22,6 @@ pub struct ParentSlotInfo {
pub parent: ObjectID, pub parent: ObjectID,
pub slot: usize, pub slot: usize,
} }
tag_object_traits! { tag_object_traits! {
#![object_trait(Object: Debug)] #![object_trait(Object: Debug)]
@@ -34,8 +33,8 @@ tag_object_traits! {
fn slots_count(&self) -> usize; fn slots_count(&self) -> usize;
fn get_slot(&self, index: usize) -> Option<&Slot>; fn get_slot(&self, index: usize) -> Option<&Slot>;
fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot>; fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot>;
fn get_slots(&self) -> &[Slot]; fn get_slots(&self) -> Vec<&Slot>;
fn get_slots_mut(&mut self) -> &mut [Slot]; fn get_slots_mut(&mut self) -> Vec<&mut Slot>;
} }
pub trait MemoryReadable { pub trait MemoryReadable {
@@ -80,16 +79,25 @@ tag_object_traits! {
&self, &self,
device: i32, device: i32,
connection: Option<usize>, connection: Option<usize>,
) -> Option<VMObject>; ) -> Option<ObjectRef>;
/// i32::MAX is db /// i32::MAX is db
fn get_logicable_from_index_mut(
&mut self,
device: i32,
connection: Option<usize>,
) -> Option<ObjectRefMut>;
fn get_logicable_from_id( fn get_logicable_from_id(
&self, &self,
device: ObjectID, device: ObjectID,
connection: Option<usize>, connection: Option<usize>,
) -> Option<VMObject>; ) -> Option<ObjectRef>;
fn get_source_code(&self) -> String; fn get_logicable_from_id_mut(
fn set_source_code(&self, code: String); &mut self,
fn get_ic(&self) -> Option<ObjectID>; device: ObjectID,
connection: Option<usize>,
) -> Option<ObjectRefMut>;
fn get_ic(&self) -> Option<VMObject>;
fn get_ic_mut(&self) -> Option<VMObject>;
fn hault_and_catch_fire(&mut self); fn hault_and_catch_fire(&mut self);
} }