refactor(vm): re impl freezing VM using ObjectTemplates
This commit is contained in:
@@ -25,7 +25,7 @@ pub enum CableConnectionType {
|
||||
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum Connection {
|
||||
CableNetwork {
|
||||
net: Option<u32>,
|
||||
net: Option<ObjectID>,
|
||||
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<ObjectID> {
|
||||
self.devices.iter().copied().collect_vec()
|
||||
}
|
||||
|
||||
fn get_power_only(&self) -> Vec<ObjectID> {
|
||||
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<u32>,
|
||||
pub power_only: Vec<u32>,
|
||||
pub channels: [f64; 8],
|
||||
}
|
||||
|
||||
impl<T> From<T> for FrozenNetwork
|
||||
impl<T> From<T> for FrozenCableNetwork
|
||||
where
|
||||
T: Deref<Target = CableNetwork>,
|
||||
{
|
||||
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<FrozenNetwork> for CableNetwork {
|
||||
fn from(value: FrozenNetwork) -> Self {
|
||||
impl From<NetworkRef<'_>> 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<FrozenCableNetwork> for CableNetwork {
|
||||
fn from(value: FrozenCableNetwork) -> Self {
|
||||
CableNetwork {
|
||||
id: value.id,
|
||||
prefab: Name::new(""),
|
||||
|
||||
@@ -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<ObjectID>,
|
||||
pub devices: Vec<ObjectID>,
|
||||
pub power_only: Vec<ObjectID>,
|
||||
}
|
||||
|
||||
@@ -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<Self>) -> 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<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()
|
||||
@@ -264,7 +267,11 @@ impl VM {
|
||||
}
|
||||
|
||||
/// returns true if executed 128 lines, false if returned early.
|
||||
pub fn run_programmable(self: &Rc<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()
|
||||
@@ -338,7 +345,11 @@ impl VM {
|
||||
.into_iter()
|
||||
}
|
||||
|
||||
pub fn get_device_same_network(self: &Rc<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 {
|
||||
@@ -347,7 +358,11 @@ impl VM {
|
||||
}
|
||||
|
||||
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))?;
|
||||
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<Self>, source: ObjectID) -> Vec<ObjectID> {
|
||||
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<Self>, id: u32, pin: usize, val: Option<ObjectID>) -> Result<bool, VMError> {
|
||||
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));
|
||||
};
|
||||
@@ -811,74 +836,117 @@ impl VM {
|
||||
Ok(last)
|
||||
}
|
||||
|
||||
pub fn save_vm_state(self: &Rc<Self>) -> 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<Self>) -> Result<FrozenVM, TemplateError> {
|
||||
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::<Result<Vec<_>, _>>()?,
|
||||
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<Self>, 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<ObjectID, VMObject> = state
|
||||
.networks
|
||||
.into_iter()
|
||||
.map(|network| (network.id, Rc::new(RefCell::new(network.into()))))
|
||||
.map(|network| {
|
||||
(
|
||||
network.id,
|
||||
VMObject::new(
|
||||
std::convert::Into::<CableNetwork>::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<VM>,
|
||||
networks: &BTreeMap<ObjectID, VMObject>,
|
||||
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<ObjectID>,
|
||||
pub program_holders: Vec<ObjectID>,
|
||||
pub default_network_key: ObjectID,
|
||||
pub networks: Vec<FrozenNetwork>,
|
||||
pub networks: Vec<FrozenCableNetwork>,
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ObjectID>;
|
||||
fn get_power_only(&self) -> Vec<ObjectID>;
|
||||
fn get_channel_data(&self) -> &[f64; 8];
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user