From 708d68e38a1ba54b0448767968207cf617936b22 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Tue, 14 May 2024 14:55:07 -0700 Subject: [PATCH] refactor(vm): re impl freezing VM using `ObjectTemplate`s --- ic10emu/src/network.rs | 38 ++++- ic10emu/src/vm.rs | 255 +++++++++++++++++++++----------- ic10emu/src/vm/object/traits.rs | 3 + 3 files changed, 203 insertions(+), 93 deletions(-) diff --git a/ic10emu/src/network.rs b/ic10emu/src/network.rs index ae87965..28c9502 100644 --- a/ic10emu/src/network.rs +++ b/ic10emu/src/network.rs @@ -25,7 +25,7 @@ pub enum CableConnectionType { #[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)] pub enum Connection { CableNetwork { - net: Option, + net: Option, typ: CableConnectionType, role: ConnectionRole, }, @@ -385,22 +385,34 @@ impl Network for CableNetwork { fn remove_power(&mut self, id: ObjectID) -> bool { self.devices.remove(&id) } + + fn get_devices(&self) -> Vec { + self.devices.iter().copied().collect_vec() + } + + fn get_power_only(&self) -> Vec { + self.power_only.iter().copied().collect_vec() + } + + fn get_channel_data(&self) -> &[f64; 8] { + &self.channels + } } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct FrozenNetwork { - pub id: u32, +pub struct FrozenCableNetwork { + pub id: ObjectID, pub devices: Vec, pub power_only: Vec, pub channels: [f64; 8], } -impl From for FrozenNetwork +impl From for FrozenCableNetwork where T: Deref, { fn from(value: T) -> Self { - FrozenNetwork { + FrozenCableNetwork { id: value.id, devices: value.devices.iter().copied().collect_vec(), power_only: value.power_only.iter().copied().collect_vec(), @@ -409,8 +421,20 @@ where } } -impl From for CableNetwork { - fn from(value: FrozenNetwork) -> Self { +impl From> for FrozenCableNetwork { + fn from(value: NetworkRef) -> Self { + FrozenCableNetwork { + id: value.get_id(), + devices: value.get_devices(), + power_only: value.get_power_only(), + channels: *value.get_channel_data(), + } + + } +} + +impl From for CableNetwork { + fn from(value: FrozenCableNetwork) -> Self { CableNetwork { id: value.id, prefab: Name::new(""), diff --git a/ic10emu/src/vm.rs b/ic10emu/src/vm.rs index 2e21495..37436b2 100644 --- a/ic10emu/src/vm.rs +++ b/ic10emu/src/vm.rs @@ -4,16 +4,12 @@ pub mod object; use crate::{ device::Device, - errors::{ICError, VMError}, + errors::{ICError, TemplateError, VMError}, interpreter::ICState, - network::{CableConnectionType, CableNetwork, Connection, ConnectionRole, FrozenNetwork}, + network::{CableConnectionType, CableNetwork, Connection, ConnectionRole, FrozenCableNetwork}, vm::{ enums::script_enums::{LogicBatchMethod, LogicSlotType, LogicType}, - object::{ - templates::ObjectTemplate, - traits::ParentSlotInfo, - ObjectID, VMObject, - }, + object::{templates::ObjectTemplate, traits::ParentSlotInfo, ObjectID, VMObject}, }, }; use std::{ @@ -44,7 +40,7 @@ pub struct VM { #[derive(Debug, Default)] pub struct VMTransactionNetwork { - pub objects: Vec, + pub devices: Vec, pub power_only: Vec, } @@ -85,7 +81,9 @@ impl VM { }); let default_network = VMObject::new(CableNetwork::new(default_network_key), vm.clone()); - vm.networks.borrow_mut().insert(default_network_key, default_network); + vm.networks + .borrow_mut() + .insert(default_network_key, default_network); vm } @@ -125,7 +123,7 @@ impl VM { .borrow_mut() .as_mut_network() .expect(&format!("non network network: {net_id}")); - for id in trans_net.objects { + for id in trans_net.devices { net.add_data(id); } for id in trans_net.power_only { @@ -138,9 +136,10 @@ impl VM { pub fn add_network(self: &Rc) -> u32 { let next_id = self.network_id_space.borrow_mut().next(); - self.networks - .borrow_mut() - .insert(next_id, VMObject::new(CableNetwork::new(next_id), self.clone())); + self.networks.borrow_mut().insert( + next_id, + VMObject::new(CableNetwork::new(next_id), self.clone()), + ); next_id } @@ -248,7 +247,11 @@ impl VM { self.operation_modified.borrow().clone() } - pub fn step_programmable(self: &Rc, id: u32, advance_ip_on_err: bool) -> Result<(), VMError> { + pub fn step_programmable( + self: &Rc, + id: u32, + advance_ip_on_err: bool, + ) -> Result<(), VMError> { let programmable = self .objects .borrow() @@ -264,7 +267,11 @@ impl VM { } /// returns true if executed 128 lines, false if returned early. - pub fn run_programmable(self: &Rc, id: u32, ignore_errors: bool) -> Result { + pub fn run_programmable( + self: &Rc, + id: u32, + ignore_errors: bool, + ) -> Result { let programmable = self .objects .borrow() @@ -338,7 +345,11 @@ impl VM { .into_iter() } - pub fn get_device_same_network(self: &Rc, source: ObjectID, other: ObjectID) -> Option { + pub fn get_device_same_network( + self: &Rc, + source: ObjectID, + other: ObjectID, + ) -> Option { if self.devices_on_same_network(&[source, other]) { self.get_object(other) } else { @@ -347,7 +358,11 @@ impl VM { } pub fn get_network_channel(self: &Rc, id: u32, channel: usize) -> Result { - let network = self.networks.borrow().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 { @@ -368,7 +383,11 @@ impl VM { channel: usize, val: f64, ) -> Result<(), ICError> { - let network = self.networks.borrow().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 { @@ -399,7 +418,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: &Rc, source: ObjectID) -> Vec { - self.networks.borrow() + self.networks + .borrow() .values() .filter_map(|net| { let net_ref = net.borrow().as_network().expect("non-network network"); @@ -412,7 +432,12 @@ impl VM { .concat() } - pub fn set_pin(self: &Rc, id: u32, pin: usize, val: Option) -> Result { + pub fn set_pin( + self: &Rc, + id: u32, + pin: usize, + val: Option, + ) -> Result { let Some(obj) = self.objects.borrow().get(&id) else { return Err(VMError::UnknownId(id)); }; @@ -811,74 +836,117 @@ impl VM { Ok(last) } - pub fn save_vm_state(self: &Rc) -> FrozenVM { - FrozenVM { - ics: self - .circuit_holders - .values() - .map(|ic| ic.borrow().into()) - .collect(), - devices: self - .devices - .values() - .map(|device| device.borrow().into()) - .collect(), + pub fn save_vm_state(self: &Rc) -> Result { + Ok(FrozenVM { + objects: self + .objects + .borrow() + .iter() + .filter_map(|(obj_id, obj)| { + if obj + .borrow() + .as_item() + .is_some_and(|item| item.get_parent_slot().is_some()) + { + None + } else { + Some(ObjectTemplate::freeze_object(obj, self)) + } + }) + .collect::, _>>()?, networks: self .networks + .borrow() .values() - .map(|network| network.borrow().into()) + .map(|network| { + network + .borrow() + .as_network() + .expect("non-network network") + .into() + }) .collect(), - default_network: self.default_network_key, - } + default_network_key: *self.default_network_key.borrow(), + circuit_holders: self.circuit_holders.borrow().clone(), + program_holders: self.program_holders.borrow().clone(), + wireless_transmitters: self.wireless_transmitters.borrow().clone(), + wireless_receivers: self.wireless_receivers.borrow().clone(), + }) } pub fn restore_vm_state(self: &Rc, state: FrozenVM) -> Result<(), VMError> { - self.circuit_holders.clear(); - self.devices.clear(); - self.networks.clear(); - self.id_space.reset(); - self.network_id_space.reset(); - - // ic ids sould be in slot occupants, don't duplicate - let to_use_ids = state - .devices - .iter() - .map(|template| { - let mut ids = template - .slots - .iter() - .filter_map(|slot| slot.occupant.as_ref().and_then(|occupant| occupant.id)) - .collect_vec(); - if let Some(id) = template.id { - ids.push(id); - } - ids - }) - .concat(); - self.id_space.use_ids(&to_use_ids)?; - - self.network_id_space + let mut transaction_network_id_space = IdSpace::new(); + transaction_network_id_space .use_ids(&state.networks.iter().map(|net| net.id).collect_vec())?; - - self.circuit_holders = state - .ics - .into_iter() - .map(|ic| (ic.id, Rc::new(RefCell::new(ic.into())))) - .collect(); - self.devices = state - .devices - .into_iter() - .map(|template| { - let device = Device::from_template(template, || self.id_space.next()); - (device.id, Rc::new(RefCell::new(device))) - }) - .collect(); - self.networks = state + let transaction_networks: BTreeMap = state .networks .into_iter() - .map(|network| (network.id, Rc::new(RefCell::new(network.into())))) + .map(|network| { + ( + network.id, + VMObject::new( + std::convert::Into::::into(network), + self.clone(), + ), + ) + }) .collect(); - self.default_network_key = state.default_network; + let mut transaction = VMTransaction::from_scratch_with_networks( + self, + &transaction_networks, + state.default_network_key, + ); + for template in state.objects { + let _ = transaction.add_device_from_template(template)?; + } + + self.circuit_holders.borrow_mut().clear(); + self.program_holders.borrow_mut().clear(); + self.objects.borrow_mut().clear(); + self.networks.borrow_mut().clear(); + self.wireless_transmitters.borrow_mut().clear(); + self.wireless_receivers.borrow_mut().clear(); + self.id_space.borrow_mut().reset(); + self.network_id_space.borrow_mut().reset(); + + self.network_id_space.replace(transaction_network_id_space); + self.networks.replace(transaction_networks); + + let transaction_ids = transaction.id_space.in_use_ids(); + self.id_space.borrow_mut().use_ids(&transaction_ids)?; + + self.circuit_holders + .borrow_mut() + .extend(transaction.circuit_holders); + self.program_holders + .borrow_mut() + .extend(transaction.program_holders); + self.wireless_transmitters + .borrow_mut() + .extend(transaction.wireless_transmitters); + self.wireless_receivers + .borrow_mut() + .extend(transaction.wireless_receivers); + + for (net_id, trans_net) in transaction.networks.into_iter() { + let net = self + .networks + .borrow() + .get(&net_id) + .expect(&format!( + "desync between vm and transaction networks: {net_id}" + )) + .borrow_mut() + .as_mut_network() + .expect(&format!("non network network: {net_id}")); + for id in trans_net.devices { + net.add_data(id); + } + for id in trans_net.power_only { + net.add_power(id); + } + } + Ok(()) } } @@ -899,7 +967,28 @@ impl VMTransaction { .keys() .map(|net_id| (*net_id, VMTransactionNetwork::default())) .collect(), - vm: vm.clone() + vm: vm.clone(), + } + } + + pub fn from_scratch_with_networks( + vm: &Rc, + networks: &BTreeMap, + default: ObjectID, + ) -> Self { + VMTransaction { + objects: BTreeMap::new(), + circuit_holders: Vec::new(), + program_holders: Vec::new(), + default_network_key: default, + wireless_transmitters: Vec::new(), + wireless_receivers: Vec::new(), + id_space: IdSpace::new(), + networks: networks + .keys() + .map(|net_id| (*net_id, VMTransactionNetwork::default())) + .collect(), + vm: vm.clone(), } } @@ -959,7 +1048,7 @@ impl VMTransaction { 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), + _ => net.devices.push(obj_id), } } else { return Err(VMError::InvalidNetwork(*net_id)); @@ -1090,13 +1179,7 @@ pub struct FrozenVM { pub circuit_holders: Vec, pub program_holders: Vec, pub default_network_key: ObjectID, - pub networks: Vec, + pub networks: Vec, pub wireless_transmitters: Vec, pub wireless_receivers: Vec, } - -impl FrozenVM { - pub fn from_vm(vm: &VM) -> Self { - let objects = vm.objects.iter().map(); - } -} diff --git a/ic10emu/src/vm/object/traits.rs b/ic10emu/src/vm/object/traits.rs index 264b37e..aa22db6 100644 --- a/ic10emu/src/vm/object/traits.rs +++ b/ic10emu/src/vm/object/traits.rs @@ -184,6 +184,9 @@ tag_object_traits! { fn remove_all(&mut self, id: ObjectID) -> bool; fn remove_data(&mut self, id: ObjectID) -> bool; fn remove_power(&mut self, id: ObjectID) -> bool; + fn get_devices(&self) -> Vec; + fn get_power_only(&self) -> Vec; + fn get_channel_data(&self) -> &[f64; 8]; }