refactor(vm): use From<T> in freeze object

This commit is contained in:
Rachel Powers
2024-05-14 00:10:48 -07:00
parent 347f5f1d59
commit d6ebbcf7e0
11 changed files with 1709 additions and 1779 deletions

View File

@@ -41,8 +41,10 @@ pub enum VMError {
#[derive(Error, Debug, Serialize, Deserialize)]
pub enum TemplateError {
#[error("")]
NonConformingObject(ObjectID)
#[error("object id {0} has a non conforming set of interfaces")]
NonConformingObject(ObjectID),
#[error("ObjectID {0} is missing fomr the VM")]
MissingVMObject(ObjectID),
}
#[derive(Debug, Clone, Serialize, Deserialize)]

View File

@@ -105,21 +105,21 @@ pub enum ConnectionRole {
impl Connection {
#[allow(dead_code)]
pub fn from_info(typ: ConnectionType, role: ConnectionRole) -> Self {
pub fn from_info(typ: ConnectionType, role: ConnectionRole, net: Option<ObjectID>) -> Self {
match typ {
ConnectionType::None => Self::None,
ConnectionType::Data => Self::CableNetwork {
net: None,
net,
typ: CableConnectionType::Data,
role,
},
ConnectionType::Power => Self::CableNetwork {
net: None,
net,
typ: CableConnectionType::Power,
role,
},
ConnectionType::PowerAndData => Self::CableNetwork {
net: None,
net,
typ: CableConnectionType::PowerAndData,
role,
},

View File

@@ -3,16 +3,16 @@ pub mod instructions;
pub mod object;
use crate::{
device::{Device, DeviceTemplate, SlotOccupant, SlotOccupantTemplate},
device::Device,
errors::{ICError, VMError},
interpreter::{self, FrozenIC, ICState, IC},
network::{CableConnectionType, CableNetwork, Connection, FrozenNetwork},
interpreter::ICState,
network::{CableConnectionType, CableNetwork, Connection, ConnectionRole, FrozenNetwork},
vm::{
enums::script_enums::{LogicBatchMethod as BatchMode, LogicSlotType, LogicType},
enums::script_enums::{LogicBatchMethod, LogicSlotType, LogicType},
object::{
templates::ObjectTemplate,
traits::{Object, ParentSlotInfo},
BoxedObject, ObjectID, VMObject,
ObjectID, VMObject,
},
},
};
@@ -27,15 +27,15 @@ use serde_derive::{Deserialize, Serialize};
#[derive(Debug)]
pub struct VM {
pub objects: BTreeMap<ObjectID, VMObject>,
pub objects: RefCell<BTreeMap<ObjectID, VMObject>>,
pub circuit_holders: RefCell<Vec<ObjectID>>,
pub program_holders: RefCell<Vec<ObjectID>>,
pub networks: BTreeMap<ObjectID, VMObject>,
pub default_network_key: ObjectID,
pub networks: RefCell<BTreeMap<ObjectID, VMObject>>,
pub default_network_key: RefCell<ObjectID>,
pub wireless_transmitters: RefCell<Vec<ObjectID>>,
pub wireless_receivers: RefCell<Vec<ObjectID>>,
id_space: IdSpace,
network_id_space: IdSpace,
id_space: RefCell<IdSpace>,
network_id_space: RefCell<IdSpace>,
random: Rc<RefCell<crate::rand_mscorlib::Random>>,
/// list of object id's touched on the last operation
@@ -60,48 +60,48 @@ pub struct VMTransation {
pub wireless_receivers: Vec<ObjectID>,
pub id_space: IdSpace,
pub networks: BTreeMap<ObjectID, VMTransationNetwork>,
}
impl Default for VM {
fn default() -> Self {
Self::new()
}
vm: Rc<VM>,
}
impl VM {
pub fn new() -> Self {
pub fn new() -> Rc<Self> {
let id_space = IdSpace::default();
let mut network_id_space = IdSpace::default();
let default_network_key = network_id_space.next();
let default_network = VMObject::new(CableNetwork::new(default_network_key));
let mut networks = BTreeMap::new();
networks.insert(default_network_key, default_network);
let networks = BTreeMap::new();
let mut vm = VM {
objects: BTreeMap::new(),
let mut vm = Rc::new(VM {
objects: RefCell::new(BTreeMap::new()),
circuit_holders: RefCell::new(Vec::new()),
program_holders: RefCell::new(Vec::new()),
networks,
default_network_key,
networks: RefCell::new(networks),
default_network_key: RefCell::new(default_network_key),
wireless_transmitters: RefCell::new(Vec::new()),
wireless_receivers: RefCell::new(Vec::new()),
id_space,
network_id_space,
id_space: RefCell::new(id_space),
network_id_space: RefCell::new(network_id_space),
random: Rc::new(RefCell::new(crate::rand_mscorlib::Random::new())),
operation_modified: RefCell::new(Vec::new()),
};
});
let default_network = VMObject::new(CableNetwork::new(default_network_key), vm.clone());
vm.networks.borrow_mut().insert(default_network_key, default_network);
vm
}
pub fn add_device_from_template(&mut self, template: ObjectTemplate) -> Result<u32, VMError> {
pub fn add_device_from_template(
self: &Rc<Self>,
template: ObjectTemplate,
) -> Result<u32, VMError> {
let mut transaction = VMTransation::new(self);
let obj_id = transaction.add_device_from_template(template)?;
let transation_ids = transaction.id_space.in_use_ids();
self.id_space.use_new_ids(&transation_ids);
self.id_space.borrow_mut().use_new_ids(&transation_ids);
self.objects.extend(transaction.objects);
self.objects.borrow_mut().extend(transaction.objects);
self.wireless_transmitters
.borrow_mut()
.extend(transaction.wireless_transmitters);
@@ -117,6 +117,7 @@ impl VM {
for (net_id, trans_net) in transaction.networks.into_iter() {
let net = self
.networks
.borrow()
.get(&net_id)
.expect(&format!(
"desync between vm and transation networks: {net_id}"
@@ -135,39 +136,43 @@ impl VM {
Ok(obj_id)
}
pub fn add_network(&mut self) -> u32 {
let next_id = self.network_id_space.next();
pub fn add_network(self: &Rc<Self>) -> u32 {
let next_id = self.network_id_space.borrow_mut().next();
self.networks
.insert(next_id, VMObject::new(CableNetwork::new(next_id)));
.borrow_mut()
.insert(next_id, VMObject::new(CableNetwork::new(next_id), self.clone()));
next_id
}
pub fn get_default_network(&self) -> VMObject {
pub fn get_default_network(self: &Rc<Self>) -> VMObject {
self.networks
.get(&self.default_network_key)
.borrow()
.get(&*self.default_network_key.borrow())
.cloned()
.expect("default network not present")
}
pub fn get_network(&self, id: u32) -> Option<VMObject> {
self.networks.get(&id).cloned()
pub fn get_network(self: &Rc<Self>, id: u32) -> Option<VMObject> {
self.networks.borrow().get(&id).cloned()
}
/// 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> {
if self.id_space.has_id(&new_id) {
pub fn change_device_id(self: &Rc<Self>, old_id: u32, new_id: u32) -> Result<(), VMError> {
if self.id_space.borrow().has_id(&new_id) {
return Err(VMError::IdInUse(new_id));
}
let obj = self
.objects
.borrow_mut()
.remove(&old_id)
.ok_or(VMError::UnknownId(old_id))?;
self.id_space.use_id(new_id)?;
self.id_space.borrow_mut().use_id(new_id)?;
obj.borrow_mut().set_id(new_id);
self.objects.insert(new_id, obj);
self.objects.borrow_mut().insert(new_id, obj);
self.objects
.borrow_mut()
.iter_mut()
.filter_map(|(_obj_id, obj)| obj.borrow_mut().as_mut_device())
.for_each(|device| {
@@ -194,7 +199,7 @@ impl VM {
*id = new_id
}
});
self.networks.iter().for_each(|(_net_id, net)| {
self.networks.borrow().iter().for_each(|(_net_id, net)| {
let net_ref = net
.borrow_mut()
.as_mut_network()
@@ -206,14 +211,15 @@ impl VM {
net_ref.add_power(new_id);
}
});
self.id_space.free_id(old_id);
self.id_space.borrow_mut().free_id(old_id);
Ok(())
}
/// Set program code if it's valid
pub fn set_code(&self, id: u32, code: &str) -> Result<bool, VMError> {
pub fn set_code(self: &Rc<Self>, id: u32, code: &str) -> Result<bool, VMError> {
let programmable = self
.objects
.borrow()
.get(&id)
.ok_or(VMError::UnknownId(id))?
.borrow_mut()
@@ -224,9 +230,10 @@ impl VM {
}
/// Set program code and translate invalid lines to Nop, collecting errors
pub fn set_code_invalid(&self, id: u32, code: &str) -> Result<bool, VMError> {
pub fn set_code_invalid(self: &Rc<Self>, id: u32, code: &str) -> Result<bool, VMError> {
let programmable = self
.objects
.borrow()
.get(&id)
.ok_or(VMError::UnknownId(id))?
.borrow_mut()
@@ -237,13 +244,14 @@ impl VM {
}
/// returns a list of device ids modified in the last operations
pub fn last_operation_modified(&self) -> Vec<u32> {
pub fn last_operation_modified(self: &Rc<Self>) -> Vec<u32> {
self.operation_modified.borrow().clone()
}
pub fn step_programmable(&self, id: u32, advance_ip_on_err: bool) -> Result<(), VMError> {
pub fn step_programmable(self: &Rc<Self>, id: u32, advance_ip_on_err: bool) -> Result<(), VMError> {
let programmable = self
.objects
.borrow()
.get(&id)
.ok_or(VMError::UnknownId(id))?
.borrow_mut()
@@ -256,9 +264,10 @@ impl VM {
}
/// returns true if executed 128 lines, false if returned early.
pub fn run_programmable(&self, id: u32, ignore_errors: bool) -> Result<bool, VMError> {
pub fn run_programmable(self: &Rc<Self>, id: u32, ignore_errors: bool) -> Result<bool, VMError> {
let programmable = self
.objects
.borrow()
.get(&id)
.ok_or(VMError::UnknownId(id))?
.borrow_mut()
@@ -284,13 +293,14 @@ impl VM {
Ok(true)
}
pub fn set_modified(&self, id: ObjectID) {
pub fn set_modified(self: &Rc<Self>, id: ObjectID) {
self.operation_modified.borrow_mut().push(id);
}
pub fn reset_programmable(&self, id: ObjectID) -> Result<bool, VMError> {
pub fn reset_programmable(self: &Rc<Self>, id: ObjectID) -> Result<bool, VMError> {
let programmable = self
.objects
.borrow()
.get(&id)
.ok_or(VMError::UnknownId(id))?
.borrow_mut()
@@ -300,17 +310,18 @@ impl VM {
Ok(true)
}
pub fn get_object(&self, id: ObjectID) -> Option<VMObject> {
self.objects.get(&id).cloned()
pub fn get_object(self: &Rc<Self>, id: ObjectID) -> Option<VMObject> {
self.objects.borrow().get(&id).cloned()
}
pub fn batch_device(
&self,
self: &Rc<Self>,
source: ObjectID,
prefab_hash: f64,
name: Option<f64>,
) -> impl Iterator<Item = &VMObject> {
) -> impl Iterator<Item = VMObject> {
self.objects
.borrow()
.iter()
.filter(move |(id, device)| {
device.borrow().as_device().is_some_and(|device| {
@@ -322,9 +333,12 @@ impl VM {
&& self.devices_on_same_network(&[source, **id])
})
.map(|(_, d)| d)
.cloned()
.collect::<Vec<_>>()
.into_iter()
}
pub fn get_device_same_network(&self, source: ObjectID, other: ObjectID) -> Option<VMObject> {
pub fn get_device_same_network(self: &Rc<Self>, source: ObjectID, other: ObjectID) -> Option<VMObject> {
if self.devices_on_same_network(&[source, other]) {
self.get_object(other)
} else {
@@ -332,8 +346,8 @@ impl VM {
}
}
pub fn get_network_channel(&self, id: u32, channel: usize) -> Result<f64, ICError> {
let network = self.networks.get(&id).ok_or(ICError::BadNetworkId(id))?;
pub fn get_network_channel(self: &Rc<Self>, id: u32, channel: usize) -> Result<f64, ICError> {
let network = self.networks.borrow().get(&id).ok_or(ICError::BadNetworkId(id))?;
if !(0..8).contains(&channel) {
Err(ICError::ChannelIndexOutOfRange(channel))
} else {
@@ -349,12 +363,12 @@ impl VM {
}
pub fn set_network_channel(
&self,
self: &Rc<Self>,
id: ObjectID,
channel: usize,
val: f64,
) -> Result<(), ICError> {
let network = self.networks.get(&(id)).ok_or(ICError::BadNetworkId(id))?;
let network = self.networks.borrow().get(&(id)).ok_or(ICError::BadNetworkId(id))?;
if !(0..8).contains(&channel) {
Err(ICError::ChannelIndexOutOfRange(channel))
} else {
@@ -369,8 +383,8 @@ impl VM {
}
}
pub fn devices_on_same_network(&self, ids: &[ObjectID]) -> bool {
for net in self.networks.values() {
pub fn devices_on_same_network(self: &Rc<Self>, ids: &[ObjectID]) -> bool {
for net in self.networks.borrow().values() {
if net
.borrow()
.as_network()
@@ -384,8 +398,8 @@ impl VM {
}
/// return a vector with the device ids the source id can see via it's connected networks
pub fn visible_devices(&self, source: ObjectID) -> Vec<ObjectID> {
self.networks
pub fn visible_devices(self: &Rc<Self>, source: ObjectID) -> Vec<ObjectID> {
self.networks.borrow()
.values()
.filter_map(|net| {
let net_ref = net.borrow().as_network().expect("non-network network");
@@ -398,12 +412,12 @@ impl VM {
.concat()
}
pub fn set_pin(&self, id: u32, pin: usize, val: Option<ObjectID>) -> Result<bool, VMError> {
let Some(obj) = self.objects.get(&id) else {
pub fn set_pin(self: &Rc<Self>, id: u32, pin: usize, val: Option<ObjectID>) -> Result<bool, VMError> {
let Some(obj) = self.objects.borrow().get(&id) else {
return Err(VMError::UnknownId(id));
};
if let Some(other_device) = val {
if !self.objects.contains_key(&other_device) {
if !self.objects.borrow().contains_key(&other_device) {
return Err(VMError::UnknownId(other_device));
}
if !self.devices_on_same_network(&[id, other_device]) {
@@ -425,12 +439,12 @@ impl VM {
}
pub fn set_device_connection(
&self,
self: &Rc<Self>,
id: ObjectID,
connection: usize,
target_net: Option<ObjectID>,
) -> Result<bool, VMError> {
let Some(obj) = self.objects.get(&id) else {
let Some(obj) = self.objects.borrow().get(&id) else {
return Err(VMError::UnknownId(id));
};
let Some(device) = obj.borrow_mut().as_mut_device() else {
@@ -443,19 +457,20 @@ impl VM {
}
// scope this borrow
let Connection::CableNetwork { net, typ } = &connections[connection] else {
let Connection::CableNetwork { net, typ, .. } = &connections[connection] else {
return Err(ICError::NotACableConnection(connection).into());
};
// remove from current network
if let Some(net) = net {
if let Some(network) = self.networks.get(net) {
if let Some(network) = self.networks.borrow().get(net) {
// if there is no other connection to this network
if connections
.iter()
.filter(|conn| {
matches!(conn, Connection::CableNetwork {
net: Some(other_net),
typ: other_typ
typ: other_typ,
..
} if other_net == net && (
!matches!(typ, CableConnectionType::Power) ||
matches!(other_typ, CableConnectionType::Data | CableConnectionType::PowerAndData))
@@ -487,12 +502,13 @@ impl VM {
let Connection::CableNetwork {
ref mut net,
ref typ,
..
} = connections[connection]
else {
return Err(ICError::NotACableConnection(connection).into());
};
if let Some(target_net) = target_net {
if let Some(network) = self.networks.get(&target_net) {
if let Some(network) = self.networks.borrow().get(&target_net) {
match typ {
CableConnectionType::Power => {
network
@@ -518,12 +534,12 @@ impl VM {
}
pub fn remove_device_from_network(
&self,
self: &Rc<Self>,
id: ObjectID,
network_id: ObjectID,
) -> Result<bool, VMError> {
if let Some(network) = self.networks.get(&network_id) {
let Some(obj) = self.objects.get(&id) else {
if let Some(network) = self.networks.borrow().get(&network_id) {
let Some(obj) = self.objects.borrow().get(&id) else {
return Err(VMError::UnknownId(id));
};
let Some(device) = obj.borrow_mut().as_mut_device() else {
@@ -549,7 +565,7 @@ impl VM {
}
pub fn set_batch_device_field(
&self,
self: &Rc<Self>,
source: ObjectID,
prefab: f64,
typ: LogicType,
@@ -558,7 +574,7 @@ impl VM {
) -> Result<(), ICError> {
self.batch_device(source, prefab, None)
.map(|device| {
self.set_modified(*device.borrow().get_id());
self.set_modified(device.borrow().get_id());
device
.borrow_mut()
.as_mut_device()
@@ -570,7 +586,7 @@ impl VM {
}
pub fn set_batch_device_slot_field(
&self,
self: &Rc<Self>,
source: ObjectID,
prefab: f64,
index: f64,
@@ -580,7 +596,7 @@ impl VM {
) -> Result<(), ICError> {
self.batch_device(source, prefab, None)
.map(|device| {
self.set_modified(*device.borrow().get_id());
self.set_modified(device.borrow().get_id());
device
.borrow_mut()
.as_mut_device()
@@ -592,7 +608,7 @@ impl VM {
}
pub fn set_batch_name_device_field(
&self,
self: &Rc<Self>,
source: ObjectID,
prefab: f64,
name: f64,
@@ -602,7 +618,7 @@ impl VM {
) -> Result<(), ICError> {
self.batch_device(source, prefab, Some(name))
.map(|device| {
self.set_modified(*device.borrow().get_id());
self.set_modified(device.borrow().get_id());
device
.borrow_mut()
.as_mut_device()
@@ -614,11 +630,11 @@ impl VM {
}
pub fn get_batch_device_field(
&self,
self: &Rc<Self>,
source: ObjectID,
prefab: f64,
typ: LogicType,
mode: BatchMode,
mode: LogicBatchMethod,
) -> Result<f64, ICError> {
let samples = self
.batch_device(source, prefab, None)
@@ -636,12 +652,12 @@ impl VM {
}
pub fn get_batch_name_device_field(
&self,
self: &Rc<Self>,
source: ObjectID,
prefab: f64,
name: f64,
typ: LogicType,
mode: BatchMode,
mode: LogicBatchMethod,
) -> Result<f64, ICError> {
let samples = self
.batch_device(source, prefab, Some(name))
@@ -659,13 +675,13 @@ impl VM {
}
pub fn get_batch_name_device_slot_field(
&self,
self: &Rc<Self>,
source: ObjectID,
prefab: f64,
name: f64,
index: f64,
typ: LogicSlotType,
mode: BatchMode,
mode: LogicBatchMethod,
) -> Result<f64, ICError> {
let samples = self
.batch_device(source, prefab, Some(name))
@@ -683,12 +699,12 @@ impl VM {
}
pub fn get_batch_device_slot_field(
&self,
self: &Rc<Self>,
source: ObjectID,
prefab: f64,
index: f64,
typ: LogicSlotType,
mode: BatchMode,
mode: LogicBatchMethod,
) -> Result<f64, ICError> {
let samples = self
.batch_device(source, prefab, None)
@@ -705,15 +721,15 @@ impl VM {
Ok(mode.apply(&samples))
}
pub fn remove_object(&mut self, id: ObjectID) -> Result<(), VMError> {
let Some(obj) = self.objects.remove(&id) else {
pub fn remove_object(self: &Rc<Self>, id: ObjectID) -> Result<(), VMError> {
let Some(obj) = self.objects.borrow_mut().remove(&id) else {
return Err(VMError::UnknownId(id));
};
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.borrow().get(&net) {
network
.borrow_mut()
.as_mut_network()
@@ -726,7 +742,7 @@ impl VM {
self.circuit_holders.borrow_mut().retain(|a| *a != id);
}
}
self.id_space.free_id(id);
self.id_space.borrow_mut().free_id(id);
Ok(())
}
@@ -735,13 +751,13 @@ impl VM {
/// does not clean up previous object
/// returns the id of any former occupant
pub fn set_slot_occupant(
&mut self,
self: &Rc<Self>,
id: ObjectID,
index: usize,
target: Option<ObjectID>,
quantity: u32,
) -> Result<Option<ObjectID>, VMError> {
let Some(obj) = self.objects.get(&id) else {
let Some(obj) = self.objects.borrow().get(&id) else {
return Err(VMError::UnknownId(id));
};
let Some(storage) = obj.borrow_mut().as_mut_storage() else {
@@ -751,7 +767,7 @@ impl VM {
.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 {
let Some(item_obj) = self.objects.borrow().get(&target) else {
return Err(VMError::UnknownId(id));
};
let Some(item) = item_obj.borrow_mut().as_mut_item() else {
@@ -776,11 +792,11 @@ impl VM {
/// returns former occupant id if any
pub fn remove_slot_occupant(
&mut self,
self: &Rc<Self>,
id: ObjectID,
index: usize,
) -> Result<Option<ObjectID>, VMError> {
let Some(obj) = self.objects.get(&id) else {
let Some(obj) = self.objects.borrow().get(&id) else {
return Err(VMError::UnknownId(id));
};
let Some(storage) = obj.borrow_mut().as_mut_storage() else {
@@ -795,7 +811,7 @@ impl VM {
Ok(last)
}
pub fn save_vm_state(&self) -> FrozenVM {
pub fn save_vm_state(self: &Rc<Self>) -> FrozenVM {
FrozenVM {
ics: self
.circuit_holders
@@ -816,7 +832,7 @@ impl VM {
}
}
pub fn restore_vm_state(&mut self, state: FrozenVM) -> Result<(), VMError> {
pub fn restore_vm_state(self: &Rc<Self>, state: FrozenVM) -> Result<(), VMError> {
self.circuit_holders.clear();
self.devices.clear();
self.networks.clear();
@@ -868,20 +884,22 @@ impl VM {
}
impl VMTransation {
pub fn new(vm: &VM) -> Self {
pub fn new(vm: &Rc<VM>) -> Self {
VMTransation {
objects: BTreeMap::new(),
circuit_holders: Vec::new(),
program_holders: Vec::new(),
default_network_key: vm.default_network_key,
default_network_key: *vm.default_network_key.borrow(),
wireless_transmitters: Vec::new(),
wireless_receivers: Vec::new(),
id_space: vm.id_space.clone(),
id_space: vm.id_space.borrow().clone(),
networks: vm
.networks
.borrow()
.keys()
.map(|net_id| (*net_id, VMTransationNetwork::default()))
.collect(),
vm: vm.clone()
}
}
@@ -902,7 +920,7 @@ impl VMTransation {
self.id_space.next()
};
let obj = template.build(obj_id);
let obj = template.build(obj_id, self.vm);
if let Some(storage) = obj.borrow_mut().as_mut_storage() {
for (slot_index, occupant_template) in
@@ -935,15 +953,16 @@ impl VMTransation {
if let Connection::CableNetwork {
net: Some(net_id),
typ,
role: ConnectionRole::None,
} = conn
{
if let Some(net) = self.networks.get_mut(net_id) {
if let Some(net) = self.networks.get_mut(&net_id) {
match typ {
CableConnectionType::Power => net.power_only.push(obj_id),
_ => net.objects.push(obj_id),
}
} else {
return Err(VMError::InvalidNetwork(*net_id));
return Err(VMError::InvalidNetwork(net_id));
}
}
}
@@ -955,19 +974,21 @@ impl VMTransation {
}
}
impl BatchMode {
impl LogicBatchMethod {
pub fn apply(&self, samples: &[f64]) -> f64 {
match self {
BatchMode::Sum => samples.iter().sum(),
LogicBatchMethod::Sum => samples.iter().sum(),
// Both c-charp and rust return NaN for 0.0/0.0 so we're good here
BatchMode::Average => samples.iter().copied().sum::<f64>() / samples.len() as f64,
LogicBatchMethod::Average => {
samples.iter().copied().sum::<f64>() / samples.len() as f64
}
// Game uses a default of Positive INFINITY for Minimum
BatchMode::Minimum => *samples
LogicBatchMethod::Minimum => *samples
.iter()
.min_by(|a, b| a.partial_cmp(b).unwrap())
.unwrap_or(&f64::INFINITY),
// Game uses default of NEG_INFINITY for Maximum
BatchMode::Maximum => *samples
LogicBatchMethod::Maximum => *samples
.iter()
.max_by(|a, b| a.partial_cmp(b).unwrap())
.unwrap_or(&f64::NEG_INFINITY),
@@ -1063,10 +1084,9 @@ impl IdSpace {
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FrozenVM {
pub objects Vec<ObjectTemplate>,
pub objects: Vec<ObjectTemplate>,
pub circuit_holders: Vec<ObjectID>,
pub program_holders: Vec<ObjectID>,
pub default_network_key: ObjectID,
@@ -1077,7 +1097,6 @@ pub struct FrozenVM {
impl FrozenVM {
pub fn from_vm(vm: &VM) -> Self {
let objects = vm.objects.iter().map()
let objects = vm.objects.iter().map();
}
}

View File

@@ -1,4 +1,9 @@
use std::{cell::RefCell, ops::{Deref, DerefMut}, rc::Rc, str::FromStr};
use std::{
cell::RefCell,
ops::{Deref, DerefMut},
rc::Rc,
str::FromStr,
};
use macro_rules_attribute::derive;
use serde_derive::{Deserialize, Serialize};
@@ -12,39 +17,55 @@ pub mod traits;
use traits::Object;
use crate::vm::enums::{basic_enums::Class as SlotClass, script_enums::LogicSlotType};
use crate::vm::{
enums::{basic_enums::Class as SlotClass, script_enums::LogicSlotType},
VM,
};
use super::enums::prefabs::StationpediaPrefab;
pub type ObjectID = u32;
pub type BoxedObject = Rc<RefCell<dyn Object<ID = ObjectID>>>;
pub type BoxedObject = Rc<RefCell<dyn Object>>;
#[derive(Debug, Clone)]
pub struct VMObject(BoxedObject);
pub struct VMObject {
obj: BoxedObject,
vm: Rc<VM>,
}
impl Deref for VMObject {
type Target = BoxedObject;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
&self.obj
}
}
impl DerefMut for VMObject {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
&mut self.obj
}
}
impl VMObject {
pub fn new<T>(val: T) -> Self
pub fn new<T>(val: T, vm: Rc<VM>) -> Self
where
T: Object<ID = ObjectID> + 'static,
T: Object + 'static,
{
VMObject(Rc::new(RefCell::new(val)))
VMObject {
obj: Rc::new(RefCell::new(val)),
vm,
}
}
pub fn set_vm(&mut self, vm: Rc<VM>) {
self.vm = vm;
}
pub fn get_vm(&self) -> &Rc<VM> {
&self.vm
}
}

View File

@@ -76,7 +76,7 @@ pub struct GenericLogicableDeviceMemoryReadable {
pub prefab: Name,
#[custom(object_name)]
pub name: Name,
pub small_grid: bool
pub small_grid: bool,
pub slots: Vec<Slot>,
pub fields: BTreeMap<LogicType, LogicField>,
pub modes: Option<BTreeMap<u32, String>>,

View File

@@ -21,7 +21,7 @@ pub trait GWStructure {
fn small_grid(&self) -> bool;
}
impl<T: GWStructure> Structure for T {
impl<T: GWStructure + Object> Structure for T {
fn is_small_grid(&self) -> bool {
self.small_grid()
}

View File

@@ -1,33 +1,32 @@
macro_rules! object_trait {
(@intf {$trait_name:ident $trt:ident}) => {
(@intf {$trt:ident}) => {
paste::paste! {
#[allow(missing_docs, unused)]
pub type [<$trt Ref>]<'a, T> = &'a dyn $trt<ID = <T as $trait_name>::ID>;
pub type [<$trt Ref>]<'a> = &'a dyn $trt;
#[allow(missing_docs, unused)]
pub type [<$trt RefMut>]<'a, T> = &'a mut dyn $trt<ID = <T as $trait_name>::ID>;
pub type [<$trt RefMut>]<'a> = &'a mut dyn $trt;
}
};
(@body $trait_name:ident { $($trt:ident),* }; ) => {
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_id(&self) -> crate::vm::object::ObjectID;
fn set_id(&mut self, id: crate::vm::object::ObjectID);
fn get_prefab(&self) -> &crate::vm::object::Name;
fn get_mut_prefab(&mut self) -> &mut crate::vm::object::Name;
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(&self) -> &dyn $trait_name;
fn as_mut_object(&mut self) -> &mut dyn $trait_name;
paste::paste! {
$(
#[inline(always)]
fn [<as_ $trt:snake>](&self) -> Option<[<$trt Ref>]<Self>> {
fn [<as_ $trt:snake>](&self) -> Option<[<$trt Ref>]> {
None
}
#[inline(always)]
fn [<as_mut_ $trt:snake>](&mut self) -> Option<[<$trt RefMut>]<Self>> {
fn [<as_mut_ $trt:snake>](&mut self) -> Option<[<$trt RefMut>]> {
None
}
)*
@@ -35,15 +34,15 @@ macro_rules! object_trait {
};
(@intf_struct $trait_name:ident { $($trt:ident),* };) => {
paste::paste! {
pub struct [<$trait_name Interfaces>]<'a, T: $trait_name> {
pub struct [<$trait_name Interfaces>]<'a> {
$(
pub [<$trt:snake>]: Option<[<$trt Ref>]<'a, T>>,
pub [<$trt:snake>]: Option<[<$trt Ref>]<'a>>,
)*
}
impl<'a, T: $trait_name> [<$trait_name Interfaces>]<'a, T> {
impl<'a> [<$trait_name Interfaces>]<'a> {
pub fn [<from_ $trait_name:snake>](obj: &'a dyn $trait_name<ID = T::ID>) -> [<$trait_name Interfaces>]<'a, T> {
pub fn [<from_ $trait_name:snake>](obj: &'a dyn $trait_name) -> [<$trait_name Interfaces>]<'a> {
[<$trait_name Interfaces>] {
$(
[<$trt:snake>]: obj.[<as_ $trt:snake>](),
@@ -56,7 +55,7 @@ macro_rules! object_trait {
};
( $trait_name:ident $(: $($bound:tt)* )? {$($trt:ident),*}) => {
$(
$crate::vm::object::macros::object_trait!{@intf {$trait_name $trt}}
$crate::vm::object::macros::object_trait!{@intf {$trt}}
)*
@@ -82,13 +81,12 @@ macro_rules! ObjectInterface {
@name $name_field:ident: $name_typ:ty;
} => {
impl $trait_name for $struct {
type ID = $id_typ;
fn get_id(&self) -> &Self::ID {
&self.$id_field
fn get_id(&self) -> crate::vm::object::ObjectID {
self.$id_field
}
fn set_id(&mut self, id: Self::ID) {
fn set_id(&mut self, id: crate::vm::object::ObjectID) {
self.$id_field = id;
}
@@ -113,23 +111,23 @@ macro_rules! ObjectInterface {
}
#[inline(always)]
fn as_object(&self) -> &dyn $trait_name<ID = Self::ID> {
fn as_object(&self) -> &dyn $trait_name {
self
}
#[inline(always)]
fn as_mut_object(&mut self) -> &mut dyn $trait_name<ID = Self::ID> {
fn as_mut_object(&mut self) -> &mut dyn $trait_name {
self
}
paste::paste!{$(
#[inline(always)]
fn [<as_ $trt:snake>](&self) -> Option<[<$trt Ref>]<Self>> {
fn [<as_ $trt:snake>](&self) -> Option<[<$trt Ref>]> {
Some(self)
}
#[inline(always)]
fn [<as_mut_ $trt:snake>](&mut self) -> Option<[<$trt RefMut>]<Self>> {
fn [<as_mut_ $trt:snake>](&mut self) -> Option<[<$trt RefMut>]> {
Some(self)
}
)*}

View File

@@ -1,4 +1,6 @@
use crate::vm::enums::prefabs::StationpediaPrefab;
use std::rc::Rc;
use crate::vm::{enums::prefabs::StationpediaPrefab, VM};
use crate::vm::object::VMObject;
use super::templates::ObjectTemplate;
@@ -7,12 +9,12 @@ use super::ObjectID;
pub mod structs;
#[allow(unused)]
pub fn object_from_prefab_template(template: &ObjectTemplate, id: ObjectID) -> Option<VMObject> {
pub fn object_from_prefab_template(template: &ObjectTemplate, id: ObjectID, vm: &Rc<VM>) -> Option<VMObject> {
let prefab = StationpediaPrefab::from_repr(template.prefab_info().prefab_hash);
match prefab {
Some(StationpediaPrefab::ItemIntegratedCircuit10) => {
Some(VMObject::new(structs::ItemIntegratedCircuit10))
}
// Some(StationpediaPrefab::ItemIntegratedCircuit10) => {
// Some(VMObject::new(structs::ItemIntegratedCircuit10))
// }
// Some(StationpediaPrefab::StructureCircuitHousing) => Some()
// Some(StationpediaPrefab::StructureRocketCircuitHousing) => Some()
_ => None,

File diff suppressed because it is too large Load Diff

View File

@@ -75,14 +75,14 @@ tag_object_traits! {
pub trait CircuitHolder: Logicable + Storage {
fn clear_error(&mut self);
fn set_error(&mut self, state: i32);
fn get_logicable_from_index(&self, device: usize, vm: &VM) -> Option<LogicableRef<Self>>;
fn get_logicable_from_index_mut(&self, device: usize, vm: &VM) -> Option<LogicableRefMut<Self>>;
fn get_logicable_from_id(&self, device: ObjectID, vm: &VM) -> Option<LogicableRef<Self>>;
fn get_logicable_from_id_mut(&self, device: ObjectID, vm: &VM) -> Option<LogicableRefMut<Self>>;
fn get_logicable_from_index(&self, device: usize, vm: &VM) -> Option<LogicableRef>;
fn get_logicable_from_index_mut(&self, device: usize, vm: &VM) -> Option<LogicableRefMut>;
fn get_logicable_from_id(&self, device: ObjectID, vm: &VM) -> Option<LogicableRef>;
fn get_logicable_from_id_mut(&self, device: ObjectID, vm: &VM) -> Option<LogicableRefMut>;
fn get_source_code(&self) -> String;
fn set_source_code(&self, code: String);
fn get_batch(&self) -> Vec<LogicableRef<Self>>;
fn get_batch_mut(&self) -> Vec<LogicableRefMut<Self>>;
fn get_batch(&self) -> Vec<LogicableRef>;
fn get_batch_mut(&self) -> Vec<LogicableRefMut>;
fn get_ic(&self) -> Option<ObjectID>;
}
@@ -99,7 +99,7 @@ tag_object_traits! {
}
pub trait IntegratedCircuit: Logicable + MemoryWritable + SourceCode + Item {
fn get_circuit_holder(&self, vm: &VM) -> Option<CircuitHolderRef<Self>>;
fn get_circuit_holder(&self, vm: &VM) -> Option<CircuitHolderRef>;
fn get_instruction_pointer(&self) -> f64;
fn set_next_instruction(&mut self, next_instruction: f64);
fn set_next_instruction_relative(&mut self, offset: f64) {
@@ -189,7 +189,7 @@ tag_object_traits! {
}
impl<T: Debug> Debug for dyn Object<ID = T> {
impl Debug for dyn Object {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,