refactor(vm): start freezeing objects impl

This commit is contained in:
Rachel Powers
2024-05-12 23:44:28 -07:00
parent 8288d8ae6f
commit 347f5f1d59
18 changed files with 1608 additions and 417 deletions

View File

@@ -522,7 +522,7 @@ impl Device {
pub fn get_fields(&self, vm: &VM) -> BTreeMap<LogicType, LogicField> {
let mut copy = self.fields.clone();
if let Some(ic_id) = &self.ic {
let ic = vm.ic_holders.get(ic_id).expect("our own ic to exist").borrow();
let ic = vm.circuit_holders.get(ic_id).expect("our own ic to exist").borrow();
copy.insert(
LogicType::LineNumber,
LogicField {
@@ -642,7 +642,7 @@ impl Device {
pub fn get_field(&self, typ: LogicType, vm: &VM) -> Result<f64, ICError> {
if typ == LogicType::LineNumber && self.ic.is_some() {
let ic = vm
.ic_holders
.circuit_holders
.get(&self.ic.unwrap())
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
.borrow();
@@ -673,7 +673,7 @@ impl Device {
Err(ICError::ReadOnlyField(typ.to_string()))
} else if typ == LogicType::LineNumber && self.ic.is_some() {
let ic = vm
.ic_holders
.circuit_holders
.get(&self.ic.unwrap())
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
.borrow();
@@ -714,7 +714,7 @@ impl Device {
&& typ == LogicSlotType::LineNumber
{
let ic = vm
.ic_holders
.circuit_holders
.get(&self.ic.unwrap())
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
.borrow();
@@ -736,7 +736,7 @@ impl Device {
let mut fields = slot.get_fields();
if slot.typ == SlotClass::ProgrammableChip && slot.occupant.is_some() && self.ic.is_some() {
let ic = vm
.ic_holders
.circuit_holders
.get(&self.ic.unwrap())
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
.borrow();

View File

@@ -32,6 +32,17 @@ pub enum VMError {
NoDevicePins(ObjectID),
#[error("object {0} has no slots")]
NotStorage(ObjectID),
#[error("object {0} is not an item")]
NotAnItem(ObjectID),
#[error("object {0} is not programmable")]
NotProgrammable(ObjectID),
}
#[derive(Error, Debug, Serialize, Deserialize)]
pub enum TemplateError {
#[error("")]
NonConformingObject(ObjectID)
}
#[derive(Debug, Clone, Serialize, Deserialize)]

View File

@@ -2030,7 +2030,7 @@ impl IC {
if ic_id == &this.id {
this.peek_addr(addr)
} else {
let ic = vm.ic_holders.get(ic_id).unwrap().borrow();
let ic = vm.circuit_holders.get(ic_id).unwrap().borrow();
ic.peek_addr(addr)
}
}?;
@@ -2063,7 +2063,7 @@ impl IC {
if ic_id == &this.id {
this.peek_addr(addr)
} else {
let ic = vm.ic_holders.get(ic_id).unwrap().borrow();
let ic = vm.circuit_holders.get(ic_id).unwrap().borrow();
ic.peek_addr(addr)
}
}?;
@@ -2092,7 +2092,7 @@ impl IC {
if ic_id == &this.id {
this.poke(addr, val)?;
} else {
let ic = vm.ic_holders.get(ic_id).unwrap().borrow();
let ic = vm.circuit_holders.get(ic_id).unwrap().borrow();
ic.poke(addr, val)?;
}
vm.set_modified(device_id);
@@ -2120,7 +2120,7 @@ impl IC {
if ic_id == &this.id {
this.poke(addr, val)?;
} else {
let ic = vm.ic_holders.get(ic_id).unwrap().borrow();
let ic = vm.circuit_holders.get(ic_id).unwrap().borrow();
ic.poke(addr, val)?;
}
vm.set_modified(device_id as u32);
@@ -2532,7 +2532,7 @@ mod tests {
let device_ref = device.borrow();
device_ref.ic.unwrap()
};
let ic_chip = vm.ic_holders.get(&ic_id).unwrap().borrow();
let ic_chip = vm.circuit_holders.get(&ic_id).unwrap().borrow();
vm.set_code(
ic,
r#"lb r0 HASH("ItemActiveVent") On Sum
@@ -2561,7 +2561,7 @@ mod tests {
let device_ref = device.borrow();
device_ref.ic.unwrap()
};
let ic_chip = vm.ic_holders.get(&ic_id).unwrap().borrow();
let ic_chip = vm.circuit_holders.get(&ic_id).unwrap().borrow();
vm.set_code(
ic,
r#"push 100

View File

@@ -2,7 +2,7 @@ use std::{collections::HashSet, ops::Deref};
use crate::vm::{
enums::script_enums::LogicType,
object::{errors::LogicError, macros::ObjectInterface, traits::*, Name, ObjectID},
object::{errors::LogicError, macros::ObjectInterface, templates::ConnectionInfo, traits::*, Name, ObjectID},
};
use itertools::Itertools;
use macro_rules_attribute::derive;
@@ -23,9 +23,28 @@ pub enum Connection {
CableNetwork {
net: Option<u32>,
typ: CableConnectionType,
role: ConnectionRole,
},
Chute {
role: ConnectionRole,
},
Pipe {
role: ConnectionRole,
},
Elevator {
role: ConnectionRole,
},
LandingPad {
role: ConnectionRole,
},
LaunchPad {
role: ConnectionRole,
},
PipeLiquid {
role: ConnectionRole,
},
#[default]
Other,
None,
}
#[derive(
@@ -86,27 +105,45 @@ pub enum ConnectionRole {
impl Connection {
#[allow(dead_code)]
fn from(typ: ConnectionType, _role: ConnectionRole) -> Self {
pub fn from_info(typ: ConnectionType, role: ConnectionRole) -> Self {
match typ {
ConnectionType::None
| ConnectionType::Chute
| ConnectionType::Pipe
| ConnectionType::Elevator
| ConnectionType::LandingPad
| ConnectionType::LaunchPad
| ConnectionType::PipeLiquid => Self::Other,
ConnectionType::None => Self::None,
ConnectionType::Data => Self::CableNetwork {
net: None,
typ: CableConnectionType::Data,
role,
},
ConnectionType::Power => Self::CableNetwork {
net: None,
typ: CableConnectionType::Power,
role,
},
ConnectionType::PowerAndData => Self::CableNetwork {
net: None,
typ: CableConnectionType::PowerAndData,
role,
},
ConnectionType::Chute => Self::Chute { role },
ConnectionType::Pipe => Self::Pipe { role },
ConnectionType::Elevator => Self::Elevator { role },
ConnectionType::LandingPad => Self::LandingPad { role },
ConnectionType::LaunchPad => Self::LaunchPad { role },
ConnectionType::PipeLiquid => Self::PipeLiquid { role },
}
}
pub fn to_info(&self) -> ConnectionInfo {
match self {
Self::None => ConnectionInfo { typ:ConnectionType::None, role: ConnectionRole::None, network: None },
Self::CableNetwork { net, typ: CableConnectionType::Data, role } => ConnectionInfo { typ: ConnectionType::Data, role, network: net },
Self::CableNetwork { net, typ: CableConnectionType::Power, role } => ConnectionInfo { typ: ConnectionType::Power, role, network: net },
Self::CableNetwork { net, typ: CableConnectionType::PowerAndData, role } => ConnectionInfo { typ: ConnectionType::PowerAndData, role, network: net },
Self::Chute { role } => ConnectionInfo { typ: ConnectionType::Chute, role, network: None },
Self::Pipe { role } => ConnectionInfo { typ: ConnectionType::Pipe, role, network: None },
Self::PipeLiquid { role } => ConnectionInfo { typ: ConnectionType::PipeLiquid, role, network: None },
Self::Elevator { role } => ConnectionInfo { typ: ConnectionType::Elevator, role, network: None },
Self::LandingPad { role } => ConnectionInfo { typ: ConnectionType::LandingPad, role, network: None },
Self::LaunchPad { role } => ConnectionInfo { typ: ConnectionType::LaunchPad, role, network: None },
}
}
}
@@ -140,6 +177,12 @@ 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] {
&vec![]
}
fn get_slots_mut(&mut self) -> &mut[crate::vm::object::Slot] {
&mut vec![]
}
}
impl Logicable for CableNetwork {
@@ -205,17 +248,24 @@ impl Logicable for CableNetwork {
fn can_slot_logic_read(
&self,
slt: crate::vm::enums::script_enums::LogicSlotType,
index: usize,
index: f64,
) -> bool {
false
}
fn get_slot_logic(
&self,
slt: crate::vm::enums::script_enums::LogicSlotType,
index: usize,
index: f64,
vm: &crate::vm::VM,
) -> Result<f64, LogicError> {
Err(LogicError::CantSlotRead(slt, index))
Err(LogicError::CantSlotRead(slt, index as usize))
}
fn valid_logic_types(&self) -> Vec<LogicType> {
use LogicType::*;
vec![Channel0, Channel1, Channel2, Channel3, Channel4, Channel5, Channel6, Channel7]
}
fn known_modes(&self) -> Option<Vec<(u32,String)>> {
None
}
}

View File

@@ -5,11 +5,15 @@ pub mod object;
use crate::{
device::{Device, DeviceTemplate, SlotOccupant, SlotOccupantTemplate},
errors::{ICError, VMError},
interpreter::{self, FrozenIC},
interpreter::{self, FrozenIC, ICState, IC},
network::{CableConnectionType, CableNetwork, Connection, FrozenNetwork},
vm::{
enums::script_enums::{LogicBatchMethod as BatchMode, LogicSlotType, LogicType},
object::{templates::ObjectTemplate, traits::*, BoxedObject, ObjectID, VMObject},
object::{
templates::ObjectTemplate,
traits::{Object, ParentSlotInfo},
BoxedObject, ObjectID, VMObject,
},
},
};
use std::{
@@ -24,7 +28,8 @@ use serde_derive::{Deserialize, Serialize};
#[derive(Debug)]
pub struct VM {
pub objects: BTreeMap<ObjectID, VMObject>,
pub ic_holders: RefCell<Vec<ObjectID>>,
pub circuit_holders: RefCell<Vec<ObjectID>>,
pub program_holders: RefCell<Vec<ObjectID>>,
pub networks: BTreeMap<ObjectID, VMObject>,
pub default_network_key: ObjectID,
pub wireless_transmitters: RefCell<Vec<ObjectID>>,
@@ -48,7 +53,8 @@ pub struct VMTransationNetwork {
/// there are errors on nested templates
pub struct VMTransation {
pub objects: BTreeMap<ObjectID, VMObject>,
pub ic_holders: Vec<ObjectID>,
pub circuit_holders: Vec<ObjectID>,
pub program_holders: Vec<ObjectID>,
pub default_network_key: ObjectID,
pub wireless_transmitters: Vec<ObjectID>,
pub wireless_receivers: Vec<ObjectID>,
@@ -73,7 +79,8 @@ impl VM {
let mut vm = VM {
objects: BTreeMap::new(),
ic_holders: RefCell::new(Vec::new()),
circuit_holders: RefCell::new(Vec::new()),
program_holders: RefCell::new(Vec::new()),
networks,
default_network_key,
wireless_transmitters: RefCell::new(Vec::new()),
@@ -101,7 +108,12 @@ impl VM {
self.wireless_receivers
.borrow_mut()
.extend(transaction.wireless_receivers);
self.ic_holders.borrow_mut().extend(transaction.ic_holders);
self.circuit_holders
.borrow_mut()
.extend(transaction.circuit_holders);
self.program_holders
.borrow_mut()
.extend(transaction.program_holders);
for (net_id, trans_net) in transaction.networks.into_iter() {
let net = self
.networks
@@ -126,51 +138,72 @@ impl VM {
pub fn add_network(&mut self) -> u32 {
let next_id = self.network_id_space.next();
self.networks
.insert(next_id, Rc::new(RefCell::new(CableNetwork::new(next_id))));
.insert(next_id, VMObject::new(CableNetwork::new(next_id)));
next_id
}
pub fn get_default_network(&self) -> Rc<RefCell<CableNetwork>> {
pub fn get_default_network(&self) -> VMObject {
self.networks
.get(&self.default_network_key)
.cloned()
.unwrap()
.expect("default network not present")
}
pub fn get_network(&self, id: u32) -> Option<Rc<RefCell<CableNetwork>>> {
pub fn get_network(&self, id: u32) -> Option<VMObject> {
self.networks.get(&id).cloned()
}
pub fn remove_ic(&mut self, id: u32) {
if self.ic_holders.remove(&id).is_some() {
self.devices.remove(&id);
}
}
/// iterate over all object borrowing them mutably, never call unless VM is not currently
/// stepping
pub fn change_device_id(&mut self, old_id: u32, new_id: u32) -> Result<(), VMError> {
self.id_space.use_id(new_id)?;
let device = self
.devices
if self.id_space.has_id(&new_id) {
return Err(VMError::IdInUse(new_id));
}
let obj = self
.objects
.remove(&old_id)
.ok_or(VMError::UnknownId(old_id))?;
device.borrow_mut().id = new_id;
self.devices.insert(new_id, device);
self.ic_holders.iter().for_each(|(_id, ic)| {
let mut ic_ref = ic.borrow_mut();
if ic_ref.device == old_id {
ic_ref.device = new_id;
}
ic_ref.pins.borrow_mut().iter_mut().for_each(|pin| {
if pin.is_some_and(|d| d == old_id) {
pin.replace(new_id);
}
self.id_space.use_id(new_id)?;
obj.borrow_mut().set_id(new_id);
self.objects.insert(new_id, obj);
self.objects
.iter_mut()
.filter_map(|(_obj_id, obj)| obj.borrow_mut().as_mut_device())
.for_each(|device| {
device.get_slots_mut().iter_mut().for_each(|slot| {
if slot.parent == old_id {
slot.parent = new_id;
}
if slot
.occupant
.is_some_and(|occupant_id| occupant_id == old_id)
{
slot.occupant = Some(new_id);
}
});
});
self.circuit_holders.borrow_mut().iter_mut().for_each(|id| {
if *id == old_id {
*id = new_id
}
});
self.program_holders.borrow_mut().iter_mut().for_each(|id| {
if *id == old_id {
*id = new_id
}
});
self.networks.iter().for_each(|(_net_id, net)| {
if let Ok(mut net_ref) = net.try_borrow_mut() {
if net_ref.devices.remove(&old_id) {
net_ref.devices.insert(new_id);
}
let net_ref = net
.borrow_mut()
.as_mut_network()
.expect("non-network network");
if net_ref.remove_data(old_id) {
net_ref.add_data(new_id);
}
if net_ref.remove_power(old_id) {
net_ref.add_power(new_id);
}
});
self.id_space.free_id(old_id);
@@ -179,39 +212,27 @@ impl VM {
/// Set program code if it's valid
pub fn set_code(&self, id: u32, code: &str) -> Result<bool, VMError> {
let device = self
.devices
let programmable = self
.objects
.get(&id)
.ok_or(VMError::UnknownId(id))?
.borrow();
let ic_id = *device.ic.as_ref().ok_or(VMError::NoIC(id))?;
let ic = self
.ic_holders
.get(&ic_id)
.ok_or(VMError::UnknownIcId(ic_id))?
.borrow();
let new_prog = interpreter::Program::try_from_code(code)?;
ic.program.replace(new_prog);
ic.code.replace(code.to_string());
.borrow_mut()
.as_mut_programmable()
.ok_or(VMError::NotProgrammable(id))?;
programmable.set_source_code(code)?;
Ok(true)
}
/// Set program code and translate invalid lines to Nop, collecting errors
pub fn set_code_invalid(&self, id: u32, code: &str) -> Result<bool, VMError> {
let device = self
.devices
let programmable = self
.objects
.get(&id)
.ok_or(VMError::UnknownId(id))?
.borrow();
let ic_id = *device.ic.as_ref().ok_or(VMError::NoIC(id))?;
let ic = self
.ic_holders
.get(&ic_id)
.ok_or(VMError::UnknownIcId(ic_id))?
.borrow_mut();
let new_prog = interpreter::Program::from_code_with_invalid(code);
ic.program.replace(new_prog);
ic.code.replace(code.to_string());
.borrow_mut()
.as_mut_programmable()
.ok_or(VMError::NotProgrammable(id))?;
programmable.set_source_code_with_invalid(code);
Ok(true)
}
@@ -220,52 +241,46 @@ impl VM {
self.operation_modified.borrow().clone()
}
pub fn step_ic(&self, id: u32, advance_ip_on_err: bool) -> Result<bool, VMError> {
pub fn step_programmable(&self, id: u32, advance_ip_on_err: bool) -> Result<(), VMError> {
let programmable = self
.objects
.get(&id)
.ok_or(VMError::UnknownId(id))?
.borrow_mut()
.as_mut_programmable()
.ok_or(VMError::NotProgrammable(id))?;
self.operation_modified.borrow_mut().clear();
let ic_id = {
let device = self.devices.get(&id).ok_or(VMError::UnknownId(id))?;
let device_ref = device.borrow();
let ic_id = device_ref.ic.as_ref().ok_or(VMError::NoIC(id))?;
*ic_id
};
self.set_modified(id);
let ic = self
.ic_holders
.get(&ic_id)
.ok_or(VMError::UnknownIcId(ic_id))?
.clone();
ic.borrow().ic.replace(0);
let result = ic.borrow().step(self, advance_ip_on_err)?;
Ok(result)
programmable.step(self, advance_ip_on_err)?;
Ok(())
}
/// returns true if executed 128 lines, false if returned early.
pub fn run_ic(&self, id: u32, ignore_errors: bool) -> Result<bool, VMError> {
pub fn run_programmable(&self, id: u32, ignore_errors: bool) -> Result<bool, VMError> {
let programmable = self
.objects
.get(&id)
.ok_or(VMError::UnknownId(id))?
.borrow_mut()
.as_mut_programmable()
.ok_or(VMError::NotProgrammable(id))?;
self.operation_modified.borrow_mut().clear();
let device = self.devices.get(&id).ok_or(VMError::UnknownId(id))?.clone();
let ic_id = *device.borrow().ic.as_ref().ok_or(VMError::NoIC(id))?;
let ic = self
.ic_holders
.get(&ic_id)
.ok_or(VMError::UnknownIcId(ic_id))?
.clone();
ic.borrow().ic.replace(0);
self.set_modified(id);
for _i in 0..128 {
if let Err(err) = ic.borrow().step(self, ignore_errors) {
if let Err(err) = programmable.step(self, ignore_errors) {
if !ignore_errors {
return Err(err.into());
}
}
if let interpreter::ICState::Yield = *ic.borrow().state.borrow() {
return Ok(false);
} else if let interpreter::ICState::Sleep(_then, _sleep_for) =
*ic.borrow().state.borrow()
{
return Ok(false);
match programmable.get_state() {
ICState::Yield => return Ok(false),
ICState::Sleep(_then, _sleep_for) => return Ok(false),
ICState::HasCaughtFire => return Ok(false),
ICState::Error(_) if !ignore_errors => return Ok(false),
_ => {}
}
}
ic.borrow().state.replace(interpreter::ICState::Yield);
programmable.set_state(ICState::Yield);
Ok(true)
}
@@ -273,22 +288,15 @@ impl VM {
self.operation_modified.borrow_mut().push(id);
}
pub fn reset_ic(&self, id: ObjectID) -> Result<bool, VMError> {
let obj = self.objects.get(&id).ok_or(VMError::UnknownId(id))?.clone();
let ic_id = obj
.borrow()
.as_mut_circuit_holder()
.map(|holder| holder.get_ic())
.flatten()
.ok_or(VMError::NoIC(id))?;
let ic = self
pub fn reset_programmable(&self, id: ObjectID) -> Result<bool, VMError> {
let programmable = self
.objects
.get(&ic_id)
.ok_or(VMError::UnknownIcId(ic_id))?
.get(&id)
.ok_or(VMError::UnknownId(id))?
.borrow_mut()
.as_mut_programmable()
.ok_or(VMError::UnknownIcId(ic_id))?;
ic.reset();
.ok_or(VMError::NotProgrammable(id))?;
programmable.reset();
Ok(true)
}
@@ -310,7 +318,7 @@ impl VM {
.get_logic(LogicType::PrefabHash)
.is_ok_and(|f| f == prefab_hash)
}) && (name.is_none()
|| name.is_some_and(|name| name == device.borrow().name().hash as f64))
|| name.is_some_and(|name| name == device.borrow().get_name().hash as f64))
&& self.devices_on_same_network(&[source, **id])
})
.map(|(_, d)| d)
@@ -550,7 +558,7 @@ impl VM {
) -> Result<(), ICError> {
self.batch_device(source, prefab, None)
.map(|device| {
self.set_modified(*device.borrow().id());
self.set_modified(*device.borrow().get_id());
device
.borrow_mut()
.as_mut_device()
@@ -572,7 +580,7 @@ impl VM {
) -> Result<(), ICError> {
self.batch_device(source, prefab, None)
.map(|device| {
self.set_modified(*device.borrow().id());
self.set_modified(*device.borrow().get_id());
device
.borrow_mut()
.as_mut_device()
@@ -594,7 +602,7 @@ impl VM {
) -> Result<(), ICError> {
self.batch_device(source, prefab, Some(name))
.map(|device| {
self.set_modified(*device.borrow().id());
self.set_modified(*device.borrow().get_id());
device
.borrow_mut()
.as_mut_device()
@@ -705,7 +713,7 @@ impl VM {
if let Some(device) = obj.borrow().as_device() {
for conn in device.connection_list().iter() {
if let Connection::CableNetwork { net: Some(net), .. } = conn {
if let Some(network) = self.networks.get(net) {
if let Some(network) = self.networks.get(&net) {
network
.borrow_mut()
.as_mut_network()
@@ -715,7 +723,7 @@ impl VM {
}
}
if let Some(_) = device.as_circuit_holder() {
self.ic_holders.borrow_mut().retain(|a| *a != id);
self.circuit_holders.borrow_mut().retain(|a| *a != id);
}
}
self.id_space.free_id(id);
@@ -736,10 +744,45 @@ impl VM {
let Some(obj) = self.objects.get(&id) else {
return Err(VMError::UnknownId(id));
};
let Some(storage) = obj.borrow_mut().as_mut_storage() else {
return Err(VMError::NotStorage(id));
};
let slot = storage
.get_slot_mut(index)
.ok_or(ICError::SlotIndexOutOfRange(index as f64))?;
if let Some(target) = target {
let Some(item_obj) = self.objects.get(&target) else {
return Err(VMError::UnknownId(id));
};
let Some(item) = item_obj.borrow_mut().as_mut_item() else {
return Err(VMError::NotAnItem(target));
};
if let Some(parent_slot_info) = item.get_parent_slot() {
self.remove_slot_occupant(parent_slot_info.parent, parent_slot_info.slot)?;
}
item.set_parent_slot(Some(ParentSlotInfo {
parent: id,
slot: index,
}));
let last = slot.occupant;
slot.occupant = Some(target);
Ok(last)
} else {
let last = slot.occupant;
slot.occupant = None;
Ok(last)
}
}
// FIXME: check that object has storage and object to be added is an item
// need to move parentage and remove object from it former slot if it has one
/// returns former occupant id if any
pub fn remove_slot_occupant(
&mut self,
id: ObjectID,
index: usize,
) -> Result<Option<ObjectID>, VMError> {
let Some(obj) = self.objects.get(&id) else {
return Err(VMError::UnknownId(id));
};
let Some(storage) = obj.borrow_mut().as_mut_storage() else {
return Err(VMError::NotStorage(id));
};
@@ -747,38 +790,15 @@ impl VM {
.get_slot_mut(index)
.ok_or(ICError::SlotIndexOutOfRange(index as f64))?;
if
if let Some(last) = slot.occupant.as_ref() {
self.id_space.free_id(last.id);
}
slot.occupant = Some(occupant);
Ok(())
}
pub fn remove_slot_occupant(&mut self, id: u32, index: usize) -> Result<(), VMError> {
let Some(device) = self.devices.get(&id) else {
return Err(VMError::UnknownId(id));
};
let mut device_ref = device.borrow_mut();
let slot = device_ref
.slots
.get_mut(index)
.ok_or(ICError::SlotIndexOutOfRange(index as f64))?;
if let Some(last) = slot.occupant.as_ref() {
self.id_space.free_id(last.id);
}
let last = slot.occupant;
slot.occupant = None;
Ok(())
Ok(last)
}
pub fn save_vm_state(&self) -> FrozenVM {
FrozenVM {
ics: self
.ic_holders
.circuit_holders
.values()
.map(|ic| ic.borrow().into())
.collect(),
@@ -797,7 +817,7 @@ impl VM {
}
pub fn restore_vm_state(&mut self, state: FrozenVM) -> Result<(), VMError> {
self.ic_holders.clear();
self.circuit_holders.clear();
self.devices.clear();
self.networks.clear();
self.id_space.reset();
@@ -824,7 +844,7 @@ impl VM {
self.network_id_space
.use_ids(&state.networks.iter().map(|net| net.id).collect_vec())?;
self.ic_holders = state
self.circuit_holders = state
.ics
.into_iter()
.map(|ic| (ic.id, Rc::new(RefCell::new(ic.into()))))
@@ -851,7 +871,8 @@ impl VMTransation {
pub fn new(vm: &VM) -> Self {
VMTransation {
objects: BTreeMap::new(),
ic_holders: Vec::new(),
circuit_holders: Vec::new(),
program_holders: Vec::new(),
default_network_key: vm.default_network_key,
wireless_transmitters: Vec::new(),
wireless_receivers: Vec::new(),
@@ -874,7 +895,7 @@ impl VMTransation {
}
}
let obj_id = if let Some(obj_id) = template.object().map(|info| info.id).flatten() {
let obj_id = if let Some(obj_id) = template.object_info().map(|info| info.id).flatten() {
self.id_space.use_id(obj_id)?;
obj_id
} else {
@@ -904,7 +925,10 @@ impl VMTransation {
self.wireless_receivers.push(obj_id);
}
if let Some(circuit_holder) = obj.borrow().as_circuit_holder() {
self.ic_holders.push(obj_id);
self.circuit_holders.push(obj_id);
}
if let Some(programmable) = obj.borrow().as_programmable() {
self.program_holders.push(obj_id);
}
if let Some(device) = obj.borrow_mut().as_mut_device() {
for conn in device.connection_list().iter() {
@@ -931,14 +955,6 @@ impl VMTransation {
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FrozenVM {
pub ics: Vec<FrozenIC>,
pub devices: Vec<DeviceTemplate>,
pub networks: Vec<FrozenNetwork>,
pub default_network: u32,
}
impl BatchMode {
pub fn apply(&self, samples: &[f64]) -> f64 {
match self {
@@ -1046,3 +1062,22 @@ impl IdSpace {
self.in_use.clear();
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FrozenVM {
pub objects Vec<ObjectTemplate>,
pub circuit_holders: Vec<ObjectID>,
pub program_holders: Vec<ObjectID>,
pub default_network_key: ObjectID,
pub networks: Vec<FrozenNetwork>,
pub wireless_transmitters: Vec<ObjectID>,
pub wireless_receivers: Vec<ObjectID>,
}
impl FrozenVM {
pub fn from_vm(vm: &VM) -> Self {
let objects = vm.objects.iter().map()
}
}

View File

@@ -24,3 +24,4 @@ pub static CONSTANTS_LOOKUP: phf::Map<&'static str, f64> = phf_map! {
"pinf" => f64::INFINITY,
"pi" => 3.141592653589793f64,
};

View File

@@ -10,7 +10,7 @@ pub mod stationpedia;
pub mod templates;
pub mod traits;
use traits::*;
use traits::Object;
use crate::vm::enums::{basic_enums::Class as SlotClass, script_enums::LogicSlotType};
@@ -105,6 +105,7 @@ pub struct Slot {
pub index: usize,
pub name: String,
pub typ: SlotClass,
pub enabled_logic: Vec<LogicSlotType>,
pub readable_logic: Vec<LogicSlotType>,
pub writeable_logic: Vec<LogicSlotType>,
pub occupant: Option<ObjectID>,
}

View File

@@ -8,13 +8,13 @@ pub enum LogicError {
#[error("can't read LogicType {0}")]
CantRead(LogicType),
#[error("can't read slot {1} LogicSlotType {0}")]
CantSlotRead(LogicSlotType, usize),
CantSlotRead(LogicSlotType, f64),
#[error("can't write LogicType {0}")]
CantWrite(LogicType),
#[error("can't write slot {1} LogicSlotType {0}")]
CantSlotWrite(LogicSlotType, usize),
CantSlotWrite(LogicSlotType, f64),
#[error("slot id {0} is out of range 0..{1}")]
SlotIndexOutOfRange(usize, usize),
SlotIndexOutOfRange(f64, usize),
}
#[derive(Error, Debug, Clone, Serialize, Deserialize)]

View File

@@ -1,3 +1,19 @@
macro_rules! GWStructure {
(
$( #[$attr:meta] )*
$viz:vis struct $struct:ident {
$($body:tt)*
}
) => {
impl GWStructure for $struct {
fn small_grid(&self) -> bool {
self.small_grid
}
}
};
}
pub(crate) use GWStructure;
macro_rules! GWStorage {
(
$( #[$attr:meta] )*
@@ -31,6 +47,9 @@ macro_rules! GWLogicable {
fn fields_mut(&mut self) -> &mut BTreeMap<LogicType, LogicField> {
&mut self.fields
}
fn modes(&self) -> Option<&BTreeMap<u32, String>> {
self.modes.as_ref()
}
}
};
}
@@ -114,6 +133,9 @@ macro_rules! GWItem {
fn parent_slot(&self) -> Option<ParentSlotInfo> {
self.parent_slot
}
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>) {
self.parent_slot = info;
}
}
};
}

View File

@@ -9,8 +9,8 @@ use crate::{network::Connection, vm::{
use macro_rules_attribute::derive;
use std::collections::BTreeMap;
#[derive(ObjectInterface!)]
#[custom(implements(Object { }))]
#[derive(ObjectInterface!, GWStructure!)]
#[custom(implements(Object { Structure }))]
pub struct Generic {
#[custom(object_id)]
pub id: ObjectID,
@@ -18,10 +18,11 @@ pub struct Generic {
pub prefab: Name,
#[custom(object_name)]
pub name: Name,
pub small_grid: bool,
}
#[derive(ObjectInterface!, GWStorage!)]
#[custom(implements(Object { Storage }))]
#[derive(ObjectInterface!, GWStructure!, GWStorage!)]
#[custom(implements(Object { Structure, Storage }))]
pub struct GenericStorage {
#[custom(object_id)]
pub id: ObjectID,
@@ -29,11 +30,12 @@ pub struct GenericStorage {
pub prefab: Name,
#[custom(object_name)]
pub name: Name,
pub small_grid: bool,
pub slots: Vec<Slot>,
}
#[derive(ObjectInterface!, GWStorage!, GWLogicable!)]
#[custom(implements(Object { Storage, Logicable }))]
#[derive(ObjectInterface!, GWStructure!, GWStorage!, GWLogicable!)]
#[custom(implements(Object { Structure, Storage, Logicable }))]
pub struct GenericLogicable {
#[custom(object_id)]
pub id: ObjectID,
@@ -41,12 +43,14 @@ pub struct GenericLogicable {
pub prefab: Name,
#[custom(object_name)]
pub name: Name,
pub fields: BTreeMap<LogicType, LogicField>,
pub small_grid: bool,
pub slots: Vec<Slot>,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
}
#[derive(ObjectInterface!, GWStorage!, GWLogicable!, GWDevice!)]
#[custom(implements(Object { Storage, Logicable, Device }))]
#[derive(ObjectInterface!, GWStructure!, GWStorage!, GWLogicable!, GWDevice!)]
#[custom(implements(Object { Structure, Storage, Logicable, Device }))]
pub struct GenericLogicableDevice {
#[custom(object_id)]
pub id: ObjectID,
@@ -54,15 +58,17 @@ pub struct GenericLogicableDevice {
pub prefab: Name,
#[custom(object_name)]
pub name: Name,
pub fields: BTreeMap<LogicType, LogicField>,
pub small_grid: bool,
pub slots: Vec<Slot>,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
pub device_info: DeviceInfo,
pub connections: Vec<Connection>,
pub pins: Option<Vec<Option<ObjectID>>>,
}
#[derive(ObjectInterface!, GWStorage!, GWLogicable!, GWDevice!, GWMemoryReadable!, GWMemoryWritable!)]
#[custom(implements(Object { Storage, Logicable, Device, MemoryReadable }))]
#[derive(ObjectInterface!, GWStructure!, GWStorage!, GWLogicable!, GWDevice!, GWMemoryReadable!, GWMemoryWritable!)]
#[custom(implements(Object { Structure, Storage, Logicable, Device, MemoryReadable }))]
pub struct GenericLogicableDeviceMemoryReadable {
#[custom(object_id)]
pub id: ObjectID,
@@ -70,16 +76,18 @@ pub struct GenericLogicableDeviceMemoryReadable {
pub prefab: Name,
#[custom(object_name)]
pub name: Name,
pub fields: BTreeMap<LogicType, LogicField>,
pub small_grid: bool
pub slots: Vec<Slot>,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
pub device_info: DeviceInfo,
pub connections: Vec<Connection>,
pub pins: Option<Vec<Option<ObjectID>>>,
pub memory: Vec<f64>,
}
#[derive(ObjectInterface!, GWStorage!, GWLogicable!, GWDevice!, GWMemoryReadable!, GWMemoryWritable!)]
#[custom(implements(Object { Storage, Logicable, Device, MemoryReadable, MemoryWritable }))]
#[derive(ObjectInterface!, GWStructure!, GWStorage!, GWLogicable!, GWDevice!, GWMemoryReadable!, GWMemoryWritable!)]
#[custom(implements(Object { Structure, Storage, Logicable, Device, MemoryReadable, MemoryWritable }))]
pub struct GenericLogicableDeviceMemoryReadWriteable {
#[custom(object_id)]
pub id: ObjectID,
@@ -87,8 +95,10 @@ pub struct GenericLogicableDeviceMemoryReadWriteable {
pub prefab: Name,
#[custom(object_name)]
pub name: Name,
pub fields: BTreeMap<LogicType, LogicField>,
pub small_grid: bool,
pub slots: Vec<Slot>,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
pub device_info: DeviceInfo,
pub connections: Vec<Connection>,
pub pins: Option<Vec<Option<ObjectID>>>,
@@ -133,8 +143,9 @@ pub struct GenericItemLogicable {
pub name: Name,
pub item_info: ItemInfo,
pub parent_slot: Option<ParentSlotInfo>,
pub fields: BTreeMap<LogicType, LogicField>,
pub slots: Vec<Slot>,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
}
#[derive(ObjectInterface!, GWItem!, GWStorage!, GWLogicable!, GWMemoryReadable! )]
@@ -148,8 +159,9 @@ pub struct GenericItemLogicableMemoryReadable {
pub name: Name,
pub item_info: ItemInfo,
pub parent_slot: Option<ParentSlotInfo>,
pub fields: BTreeMap<LogicType, LogicField>,
pub slots: Vec<Slot>,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
pub memory: Vec<f64>,
}
@@ -164,7 +176,8 @@ pub struct GenericItemLogicableMemoryReadWriteable {
pub name: Name,
pub item_info: ItemInfo,
pub parent_slot: Option<ParentSlotInfo>,
pub fields: BTreeMap<LogicType, LogicField>,
pub slots: Vec<Slot>,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,
pub memory: Vec<f64>,
}

View File

@@ -1,16 +1,32 @@
use crate::{network::Connection, vm::{
enums::{
basic_enums::{Class as SlotClass, GasType, SortingClass},
script_enums::{LogicSlotType, LogicType},
use crate::{
network::Connection,
vm::{
enums::{
basic_enums::{Class as SlotClass, GasType, SortingClass},
script_enums::{LogicSlotType, LogicType},
},
object::{
errors::{LogicError, MemoryError},
templates::{DeviceInfo, ItemInfo},
traits::*,
LogicField, MemoryAccess, ObjectID, Slot,
},
VM,
},
object::{
errors::{LogicError, MemoryError}, templates::{DeviceInfo, ItemInfo}, traits::*, LogicField, MemoryAccess, ObjectID, Slot
},
VM,
}};
};
use std::{collections::BTreeMap, usize};
use strum::IntoEnumIterator;
pub trait GWStructure {
fn small_grid(&self) -> bool;
}
impl<T: GWStructure> Structure for T {
fn is_small_grid(&self) -> bool {
self.small_grid()
}
}
pub trait GWStorage {
fn slots(&self) -> &Vec<Slot>;
fn slots_mut(&mut self) -> &mut Vec<Slot>;
@@ -26,19 +42,26 @@ impl<T: GWStorage + Object> 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_mut(&mut self) -> &mut [Slot] {
self.slots_mut()
}
}
pub trait GWLogicable: Storage {
fn fields(&self) -> &BTreeMap<LogicType, LogicField>;
fn fields_mut(&mut self) -> &mut BTreeMap<LogicType, LogicField>;
fn modes(&self) -> Option<&BTreeMap<u32, String>>;
}
impl<T: GWLogicable + Object> Logicable for T {
fn prefab_hash(&self) -> i32 {
self.prefab().hash
self.get_prefab().hash
}
fn name_hash(&self) -> i32 {
self.name().hash
self.get_name().hash
}
fn is_logic_readable(&self) -> bool {
LogicType::iter().any(|lt| self.can_logic_read(lt))
@@ -93,21 +116,23 @@ impl<T: GWLogicable + Object> Logicable for T {
_ => Err(LogicError::CantWrite(lt)),
})
}
fn can_slot_logic_read(&self, slt: LogicSlotType, index: usize) -> bool {
self.get_slot(index)
.map(|slot| slot.enabled_logic.contains(&slt))
.unwrap_or(false)
fn can_slot_logic_read(&self, slt: LogicSlotType, index: f64) -> bool {
if index < 0.0 {
false
} else {
self.get_slot(index as usize)
.map(|slot| slot.readable_logic.contains(&slt))
.unwrap_or(false)
}
}
fn get_slot_logic(
&self,
slt: LogicSlotType,
index: usize,
_vm: &VM,
) -> Result<f64, LogicError> {
self.get_slot(index)
fn get_slot_logic(&self, slt: LogicSlotType, index: f64, _vm: &VM) -> Result<f64, LogicError> {
if index < 0.0 {
return Err(LogicError::SlotIndexOutOfRange(index, self.slots_count()));
}
self.get_slot(index as usize)
.ok_or_else(|| LogicError::SlotIndexOutOfRange(index, self.slots_count()))
.and_then(|slot| {
if slot.enabled_logic.contains(&slt) {
if slot.readable_logic.contains(&slt) {
match slot.occupant {
Some(_id) => {
// FIXME: impliment by accessing VM to get occupant
@@ -120,6 +145,12 @@ impl<T: GWLogicable + Object> Logicable for T {
}
})
}
fn valid_logic_types(&self) -> Vec<LogicType> {
self.fields().keys().copied().collect()
}
fn known_modes(&self) -> Option<Vec<(u32,String)>> {
self.modes().map(|modes| modes.iter().collect())
}
}
pub trait GWMemoryReadable {
@@ -140,6 +171,9 @@ impl<T: GWMemoryReadable + Object> MemoryReadable for T {
Ok(self.memory()[index as usize])
}
}
fn get_memory_slice(&self) -> &[f64] {
self.memory()
}
}
pub trait GWMemoryWritable: MemoryReadable {
@@ -163,7 +197,7 @@ impl<T: GWMemoryWritable + MemoryReadable + Object> MemoryWritable for T {
}
}
pub trait GWDevice: Logicable {
pub trait GWDevice: GWLogicable + Logicable {
fn device_info(&self) -> &DeviceInfo;
fn device_connections(&self) -> &[Connection];
fn device_connections_mut(&mut self) -> &mut [Connection];
@@ -172,16 +206,52 @@ pub trait GWDevice: Logicable {
}
impl<T: GWDevice + Object> Device for T {
fn connection_list(&self) -> &[crate::network::Connection] {
fn can_slot_logic_write(&self, slt: LogicSlotType, index: f64) -> bool {
if index < 0.0 {
return false;
} else {
self.get_slot(index as usize)
.map(|slot| slot.writeable_logic.contains(&slt))
.unwrap_or(false)
}
}
fn set_slot_logic(
&mut self,
slt: LogicSlotType,
index: f64,
value: f64,
vm: &VM,
force: bool,
) -> Result<(), LogicError> {
if index < 0.0 {
return Err(LogicError::SlotIndexOutOfRange(index, self.slots_count()));
}
self.get_slot_mut(index as usize)
.ok_or_else(|| LogicError::SlotIndexOutOfRange(index, self.slots_count()))
.and_then(|slot| {
if slot.writeable_logic.contains(&slt) {
match slot.occupant {
Some(_id) => {
// FIXME: impliment by accessing VM to get occupant
Ok(())
}
None => Ok(()),
}
} else {
Err(LogicError::CantSlotWrite(slt, index))
}
})
}
fn connection_list(&self) -> &[crate::network::Connection] {
self.device_connections()
}
fn connection_list_mut(&mut self) -> &mut[Connection] {
fn connection_list_mut(&mut self) -> &mut [Connection] {
self.device_connections_mut()
}
fn device_pins(&self) -> Option<&[Option<ObjectID>]> {
self.device_pins()
}
fn device_pins_mut(&self) -> Option<&mut[Option<ObjectID>]> {
fn device_pins_mut(&self) -> Option<&mut [Option<ObjectID>]> {
self.device_pins_mut()
}
fn has_reagents(&self) -> bool {
@@ -199,14 +269,21 @@ impl<T: GWDevice + Object> Device for T {
fn has_on_off_state(&self) -> bool {
self.device_info().has_on_off_state
}
fn has_color_state(&self) -> bool {
self.device_info().has_color_state
}
fn has_activate_state(&self) -> bool {
self.device_info().has_activate_state
}
fn has_atmosphere(&self) -> bool {
self.device_info().has_atmosphere
}
}
pub trait GWItem {
fn item_info(&self) -> &ItemInfo;
fn parent_slot(&self) -> Option<ParentSlotInfo>;
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>);
}
impl<T: GWItem + Object> Item for T {
@@ -231,9 +308,12 @@ impl<T: GWItem + Object> Item for T {
fn sorting_class(&self) -> SortingClass {
self.item_info().sorting_class
}
fn parent_slot(&self) -> Option<ParentSlotInfo> {
fn get_parent_slot(&self) -> Option<ParentSlotInfo> {
self.parent_slot()
}
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>) {
self.set_parent_slot(info);
}
}
pub trait GWCircuitHolder: Logicable {}

View File

@@ -8,30 +8,51 @@ macro_rules! object_trait {
}
};
(@body $trait_name:ident { $($trt:ident),* }; ) => {
type ID;
fn id(&self) -> &Self::ID;
fn prefab(&self) -> &crate::vm::object::Name;
fn name(&self) -> &crate::vm::object::Name;
type ID: std::cmp::Ord + std::cmp::Eq + std::hash::Hash;
fn get_id(&self) -> &Self::ID;
fn set_id(&mut self, id: Self::ID);
fn get_prefab(&self) -> &crate::vm::object::Name;
fn get_mut_prefab(&mut self) -> &mut crate::vm::object::Name;
fn get_name(&self) -> &crate::vm::object::Name;
fn get_mut_name(&mut self) -> &mut crate::vm::object::Name;
fn type_name(&self) -> &str;
fn as_object(&self) -> &dyn $trait_name<ID = Self::ID>;
fn as_mut_object(&mut self) -> &mut dyn $trait_name<ID = Self::ID>;
fn as_object_mut(&mut self) -> &mut dyn $trait_name<ID = Self::ID>;
$(
paste::paste! {
#[inline(always)]
fn [<as_ $trt:snake>](&self) -> Option<[<$trt Ref>]<Self>> {
None
}
$(
#[inline(always)]
fn [<as_ $trt:snake>](&self) -> Option<[<$trt Ref>]<Self>> {
None
}
#[inline(always)]
fn [<as_mut_ $trt:snake>](&mut self) -> Option<[<$trt RefMut>]<Self>> {
None
#[inline(always)]
fn [<as_mut_ $trt:snake>](&mut self) -> Option<[<$trt RefMut>]<Self>> {
None
}
)*
}
};
(@intf_struct $trait_name:ident { $($trt:ident),* };) => {
paste::paste! {
pub struct [<$trait_name Interfaces>]<'a, T: $trait_name> {
$(
pub [<$trt:snake>]: Option<[<$trt Ref>]<'a, T>>,
)*
}
impl<'a, T: $trait_name> [<$trait_name Interfaces>]<'a, T> {
pub fn [<from_ $trait_name:snake>](obj: &'a dyn $trait_name<ID = T::ID>) -> [<$trait_name Interfaces>]<'a, T> {
[<$trait_name Interfaces>] {
$(
[<$trt:snake>]: obj.[<as_ $trt:snake>](),
)*
}
}
}
}
)*
};
( $trait_name:ident $(: $($bound:tt)* )? {$($trt:ident),*}) => {
$(
@@ -44,6 +65,8 @@ macro_rules! object_trait {
$crate::vm::object::macros::object_trait!{@body $trait_name {$($trt),*}; }
}
$crate::vm::object::macros::object_trait!{@intf_struct $trait_name {$($trt),*}; }
};
}
@@ -61,18 +84,30 @@ macro_rules! ObjectInterface {
impl $trait_name for $struct {
type ID = $id_typ;
fn id(&self) -> &Self::ID {
fn get_id(&self) -> &Self::ID {
&self.$id_field
}
fn prefab(&self) -> &$prefab_typ {
fn set_id(&mut self, id: Self::ID) {
self.$id_field = id;
}
fn get_prefab(&self) -> &$prefab_typ {
&self.$prefab_field
}
fn name(&self) -> &$name_typ {
fn get_mut_prefab(&mut self) -> &mut $prefab_typ {
&mut self.$prefab_field
}
fn get_name(&self) -> &$name_typ {
&self.$name_field
}
fn get_mut_name(&mut self) -> &mut $name_typ {
&mut self.$name_field
}
fn type_name(&self) -> &str {
std::any::type_name::<Self>()
}
@@ -83,7 +118,7 @@ macro_rules! ObjectInterface {
}
#[inline(always)]
fn as_object_mut(&mut self) -> &mut dyn $trait_name<ID = Self::ID> {
fn as_mut_object(&mut self) -> &mut dyn $trait_name<ID = Self::ID> {
self
}
@@ -527,7 +562,7 @@ macro_rules! tag_object_traits {
$crate::vm::object::macros::tag_object_traits!{
@tag
tag=$trt_name $(: $($obj_bound)* )?;
acc={ $trt, $($tagged_trt,)* };
acc={ $($tagged_trt,)* $trt, };
$($used)*
}
};

View File

@@ -8,7 +8,7 @@ pub mod structs;
#[allow(unused)]
pub fn object_from_prefab_template(template: &ObjectTemplate, id: ObjectID) -> Option<VMObject> {
let prefab = StationpediaPrefab::from_repr(template.prefab().prefab_hash);
let prefab = StationpediaPrefab::from_repr(template.prefab_info().prefab_hash);
match prefab {
Some(StationpediaPrefab::ItemIntegratedCircuit10) => {
Some(VMObject::new(structs::ItemIntegratedCircuit10))

View File

@@ -200,9 +200,12 @@ impl Item for ItemIntegratedCircuit10 {
fn sorting_class(&self) -> SortingClass {
SortingClass::Default
}
fn parent_slot(&self) -> Option<ParentSlotInfo> {
fn get_parent_slot(&self) -> Option<ParentSlotInfo> {
self.parent_slot
}
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>) {
self.parent_slot = info;
}
}
impl Storage for ItemIntegratedCircuit10 {
@@ -270,9 +273,7 @@ impl SourceCode for ItemIntegratedCircuit10 {
impl IntegratedCircuit for ItemIntegratedCircuit10 {
fn get_circuit_holder(&self, vm: &VM) -> Option<CircuitHolderRef> {
// FIXME: implement correctly
self.parent_slot().map(|parent_slot| {
parent_slot.parent
})
self.get_parent_slot().map(|parent_slot| parent_slot.parent)
}
fn get_instruction_pointer(&self) -> f64 {
self.ip as f64

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,7 @@
use serde_derive::{Deserialize, Serialize};
use crate::{
errors::ICError,
network::Connection,
vm::{
errors::ICError, interpreter::ICState, network::Connection, vm::{
enums::{
basic_enums::{Class as SlotClass, GasType, SortingClass},
script_enums::{LogicSlotType, LogicType},
@@ -15,7 +13,7 @@ use crate::{
ObjectID, Slot,
},
VM,
},
}
};
use std::{collections::BTreeMap, fmt::Debug};
@@ -28,20 +26,27 @@ pub struct ParentSlotInfo {
tag_object_traits! {
#![object_trait(Object: Debug)]
pub trait MemoryReadable {
fn memory_size(&self) -> usize;
fn get_memory(&self, index: i32) -> Result<f64, MemoryError>;
}
pub trait MemoryWritable: MemoryReadable {
fn set_memory(&mut self, index: i32, val: f64) -> Result<(), MemoryError>;
fn clear_memory(&mut self) -> Result<(), MemoryError>;
pub trait Structure {
fn is_small_grid(&self) -> bool;
}
pub trait Storage {
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];
}
pub trait MemoryReadable {
fn memory_size(&self) -> usize;
fn get_memory(&self, index: i32) -> Result<f64, MemoryError>;
fn get_memory_slice(&self) -> &[f64];
}
pub trait MemoryWritable: MemoryReadable {
fn set_memory(&mut self, index: i32, val: f64) -> Result<(), MemoryError>;
fn clear_memory(&mut self) -> Result<(), MemoryError>;
}
pub trait Logicable: Storage {
@@ -54,9 +59,10 @@ tag_object_traits! {
fn can_logic_write(&self, lt: LogicType) -> bool;
fn set_logic(&mut self, lt: LogicType, value: f64, force: bool) -> Result<(), LogicError>;
fn get_logic(&self, lt: LogicType) -> Result<f64, LogicError>;
fn can_slot_logic_read(&self, slt: LogicSlotType, index: f64) -> bool;
fn get_slot_logic(&self, slt: LogicSlotType, index: f64, vm: &VM) -> Result<f64, LogicError>;
fn valid_logic_types(&self) -> Vec<LogicType>;
fn known_modes(&self) -> Option<Vec<(u32, String)>>;
}
pub trait SourceCode {
@@ -88,7 +94,8 @@ tag_object_traits! {
fn reagents(&self) -> Option<&BTreeMap<String, f64>>;
fn slot_class(&self) -> SlotClass;
fn sorting_class(&self) -> SortingClass;
fn parent_slot(&self) -> Option<ParentSlotInfo>;
fn get_parent_slot(&self) -> Option<ParentSlotInfo>;
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>);
}
pub trait IntegratedCircuit: Logicable + MemoryWritable + SourceCode + Item {
@@ -114,12 +121,14 @@ tag_object_traits! {
fn get_aliases(&self) -> &BTreeMap<String, crate::vm::instructions::operands::Operand>;
fn get_defines(&self) -> &BTreeMap<String, f64>;
fn get_labels(&self) -> &BTreeMap<String, u32>;
fn get_state(&self) -> ICState;
fn set_state(&mut self, state: ICState);
}
pub trait Programmable: ICInstructable {
fn get_source_code(&self) -> String;
fn set_source_code(&self, code: String);
fn step(&mut self) -> Result<(), crate::errors::ICError>;
fn step(&mut self, vm: &VM, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError>;
}
pub trait Instructable: MemoryWritable {
@@ -131,6 +140,7 @@ tag_object_traits! {
}
pub trait Device: Logicable {
fn can_slot_logic_write(&self, slt: LogicSlotType, index: f64) -> bool;
fn set_slot_logic(
&mut self,
slt: LogicSlotType,
@@ -144,6 +154,8 @@ tag_object_traits! {
fn device_pins(&self) -> Option<&[Option<ObjectID>]>;
fn device_pins_mut(&self) -> Option<&mut [Option<ObjectID>]>;
fn has_activate_state(&self) -> bool;
fn has_atmosphere(&self) -> bool;
fn has_color_state(&self) -> bool;
fn has_lock_state(&self) -> bool;
fn has_mode_state(&self) -> bool;
fn has_on_off_state(&self) -> bool;
@@ -182,7 +194,7 @@ impl<T: Debug> Debug for dyn Object<ID = T> {
write!(
f,
"Object: (ID = {:?}, Type = {})",
self.id(),
self.get_id(),
self.type_name()
)
}

View File

@@ -107,7 +107,7 @@ impl DeviceRef {
self.device.borrow().ic.as_ref().and_then(|ic| {
self.vm
.borrow()
.ic_holders
.circuit_holders
.get(ic)
.map(|ic| ic.as_ref().borrow().ip())
})
@@ -118,7 +118,7 @@ impl DeviceRef {
self.device.borrow().ic.as_ref().and_then(|ic| {
self.vm
.borrow()
.ic_holders
.circuit_holders
.get(ic)
.map(|ic| ic.as_ref().borrow().ic.get())
})
@@ -129,7 +129,7 @@ impl DeviceRef {
self.device.borrow().ic.as_ref().and_then(|ic| {
self.vm
.borrow()
.ic_holders
.circuit_holders
.get(ic)
.map(|ic| Stack(*ic.as_ref().borrow().stack.borrow()))
})
@@ -140,7 +140,7 @@ impl DeviceRef {
self.device.borrow().ic.as_ref().and_then(|ic| {
self.vm
.borrow()
.ic_holders
.circuit_holders
.get(ic)
.map(|ic| Registers(*ic.as_ref().borrow().registers.borrow()))
})
@@ -151,7 +151,7 @@ impl DeviceRef {
let aliases = &self.device.borrow().ic.as_ref().and_then(|ic| {
self.vm
.borrow()
.ic_holders
.circuit_holders
.get(ic)
.map(|ic| ic.as_ref().borrow().aliases.borrow().clone())
});
@@ -163,7 +163,7 @@ impl DeviceRef {
let defines = &self.device.borrow().ic.as_ref().and_then(|ic| {
self.vm
.borrow()
.ic_holders
.circuit_holders
.get(ic)
.map(|ic| ic.as_ref().borrow().defines.borrow().clone())
});
@@ -175,7 +175,7 @@ impl DeviceRef {
let pins = &self.device.borrow().ic.as_ref().and_then(|ic| {
self.vm
.borrow()
.ic_holders
.circuit_holders
.get(ic)
.map(|ic| *ic.as_ref().borrow().pins.borrow())
});
@@ -191,7 +191,7 @@ impl DeviceRef {
.and_then(|ic| {
self.vm
.borrow()
.ic_holders
.circuit_holders
.get(ic)
.map(|ic| ic.borrow().state.clone())
})
@@ -203,7 +203,7 @@ impl DeviceRef {
let prog = &self.device.borrow().ic.as_ref().and_then(|ic| {
self.vm
.borrow()
.ic_holders
.circuit_holders
.get(ic)
.map(|ic| ic.borrow().program.borrow().clone())
});
@@ -215,7 +215,7 @@ impl DeviceRef {
self.device.borrow().ic.as_ref().and_then(|ic| {
self.vm
.borrow()
.ic_holders
.circuit_holders
.get(ic)
.map(|ic| ic.borrow().code.borrow().clone())
})
@@ -263,7 +263,7 @@ impl DeviceRef {
.ok_or(VMError::NoIC(self.device.borrow().id))?;
let vm_borrow = self.vm.borrow();
let ic = vm_borrow
.ic_holders
.circuit_holders
.get(&ic_id)
.ok_or(VMError::NoIC(self.device.borrow().id))?;
let result = ic.borrow_mut().set_register(0, index, val)?;
@@ -280,7 +280,7 @@ impl DeviceRef {
.ok_or(VMError::NoIC(self.device.borrow().id))?;
let vm_borrow = self.vm.borrow();
let ic = vm_borrow
.ic_holders
.circuit_holders
.get(&ic_id)
.ok_or(VMError::NoIC(self.device.borrow().id))?;
let result = ic.borrow_mut().poke(address, val)?;
@@ -433,7 +433,7 @@ impl VMRef {
#[wasm_bindgen(getter)]
pub fn ics(&self) -> Vec<u32> {
self.vm.borrow().ic_holders.keys().copied().collect_vec()
self.vm.borrow().circuit_holders.keys().copied().collect_vec()
}
#[wasm_bindgen(getter, js_name = "lastOperationModified")]

3
rust-analyzer.json Normal file
View File

@@ -0,0 +1,3 @@
{
"rust-analyzer.cargo.target": "wasm32-unknown-unknown"
}