From de2698c2e23c8530a49270b3881af9b1349ae1f8 Mon Sep 17 00:00:00 2001 From: Rachel Powers <508861+Ryex@users.noreply.github.com> Date: Tue, 14 May 2024 05:13:12 -0700 Subject: [PATCH] refactor(vm): VMObjects should carry around a VM reference --- ic10emu/src/network.rs | 97 ++++- ic10emu/src/vm/object.rs | 26 +- ic10emu/src/vm/object/generic/macros.rs | 2 +- ic10emu/src/vm/object/generic/structs.rs | 26 +- ic10emu/src/vm/object/generic/traits.rs | 13 +- ic10emu/src/vm/object/macros.rs | 372 ++++++------------ .../structs/integrated_circuit.rs | 130 ++++-- ic10emu/src/vm/object/templates.rs | 23 +- ic10emu/src/vm/object/traits.rs | 4 +- 9 files changed, 370 insertions(+), 323 deletions(-) diff --git a/ic10emu/src/network.rs b/ic10emu/src/network.rs index 58fa0ef..ae87965 100644 --- a/ic10emu/src/network.rs +++ b/ic10emu/src/network.rs @@ -1,8 +1,12 @@ -use std::{collections::HashSet, ops::Deref}; +use std::{collections::HashSet, ops::Deref, rc::Rc}; use crate::vm::{ enums::script_enums::LogicType, - object::{errors::LogicError, macros::ObjectInterface, templates::ConnectionInfo, traits::*, Name, ObjectID}, + object::{ + errors::LogicError, macros::ObjectInterface, templates::ConnectionInfo, traits::*, Name, + ObjectID, + }, + VM, }; use itertools::Itertools; use macro_rules_attribute::derive; @@ -134,16 +138,68 @@ impl Connection { 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 }, + Self::None => ConnectionInfo { + typ: ConnectionType::None, + role: ConnectionRole::None, + network: None, + }, + Self::CableNetwork { + net, + typ: CableConnectionType::Data, + role, + } => ConnectionInfo { + typ: ConnectionType::Data, + role: *role, + network: *net, + }, + Self::CableNetwork { + net, + typ: CableConnectionType::Power, + role, + } => ConnectionInfo { + typ: ConnectionType::Power, + role: *role, + network: *net, + }, + Self::CableNetwork { + net, + typ: CableConnectionType::PowerAndData, + role, + } => ConnectionInfo { + typ: ConnectionType::PowerAndData, + role: *role, + network: *net, + }, + Self::Chute { role } => ConnectionInfo { + typ: ConnectionType::Chute, + role: *role, + network: None, + }, + Self::Pipe { role } => ConnectionInfo { + typ: ConnectionType::Pipe, + role: *role, + network: None, + }, + Self::PipeLiquid { role } => ConnectionInfo { + typ: ConnectionType::PipeLiquid, + role: *role, + network: None, + }, + Self::Elevator { role } => ConnectionInfo { + typ: ConnectionType::Elevator, + role: *role, + network: None, + }, + Self::LandingPad { role } => ConnectionInfo { + typ: ConnectionType::LandingPad, + role: *role, + network: None, + }, + Self::LaunchPad { role } => ConnectionInfo { + typ: ConnectionType::LaunchPad, + role: *role, + network: None, + }, } } } @@ -159,6 +215,9 @@ pub struct CableNetwork { #[custom(object_name)] /// required by object interface but atm unused by network pub name: Name, + #[custom(object_vm_ref)] + #[serde(skip)] + pub vm: Option>, /// data enabled objects (must be devices) pub devices: HashSet, /// power only connections @@ -177,10 +236,10 @@ 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] { + fn get_slots(&self) -> &[crate::vm::object::Slot] { &vec![] } - fn get_slots_mut(&mut self) -> &mut[crate::vm::object::Slot] { + fn get_slots_mut(&mut self) -> &mut [crate::vm::object::Slot] { &mut vec![] } } @@ -258,13 +317,15 @@ impl Logicable for CableNetwork { index: f64, vm: &crate::vm::VM, ) -> Result { - Err(LogicError::CantSlotRead(slt, index as usize)) + Err(LogicError::CantSlotRead(slt, index)) } fn valid_logic_types(&self) -> Vec { use LogicType::*; - vec![Channel0, Channel1, Channel2, Channel3, Channel4, Channel5, Channel6, Channel7] + vec![ + Channel0, Channel1, Channel2, Channel3, Channel4, Channel5, Channel6, Channel7, + ] } - fn known_modes(&self) -> Option> { + fn known_modes(&self) -> Option> { None } } @@ -354,6 +415,7 @@ impl From for CableNetwork { id: value.id, prefab: Name::new(""), name: Name::new(""), + vm: None, devices: value.devices.into_iter().collect(), power_only: value.power_only.into_iter().collect(), channels: value.channels, @@ -373,6 +435,7 @@ impl CableNetwork { id, prefab: Name::new(""), name: Name::new(""), + vm: None, devices: HashSet::new(), power_only: HashSet::new(), channels: [f64::NAN; 8], diff --git a/ic10emu/src/vm/object.rs b/ic10emu/src/vm/object.rs index c0b3831..f8ff659 100644 --- a/ic10emu/src/vm/object.rs +++ b/ic10emu/src/vm/object.rs @@ -28,24 +28,21 @@ pub type ObjectID = u32; pub type BoxedObject = Rc>; #[derive(Debug, Clone)] -pub struct VMObject { - obj: BoxedObject, - vm: Rc, -} +pub struct VMObject(BoxedObject); impl Deref for VMObject { type Target = BoxedObject; #[inline(always)] fn deref(&self) -> &Self::Target { - &self.obj + &self.0 } } impl DerefMut for VMObject { #[inline(always)] fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.obj + &mut self.0 } } @@ -54,18 +51,21 @@ impl VMObject { where T: Object + 'static, { - VMObject { - obj: Rc::new(RefCell::new(val)), - vm, - } + let mut obj = VMObject(Rc::new(RefCell::new(val))); + obj.set_vm(vm); + obj } pub fn set_vm(&mut self, vm: Rc) { - self.vm = vm; + self.borrow_mut().set_vm(vm); } - pub fn get_vm(&self) -> &Rc { - &self.vm + pub fn get_vm(&self) -> Rc { + self + .borrow() + .get_vm() + .expect("VMObject with no VM?") + .clone() } } diff --git a/ic10emu/src/vm/object/generic/macros.rs b/ic10emu/src/vm/object/generic/macros.rs index 0de9aff..7232e7d 100644 --- a/ic10emu/src/vm/object/generic/macros.rs +++ b/ic10emu/src/vm/object/generic/macros.rs @@ -47,7 +47,7 @@ macro_rules! GWLogicable { fn fields_mut(&mut self) -> &mut BTreeMap { &mut self.fields } - fn modes(&self) -> Option<&BTreeMap> { + fn known_modes(&self) -> Option<&BTreeMap> { self.modes.as_ref() } } diff --git a/ic10emu/src/vm/object/generic/structs.rs b/ic10emu/src/vm/object/generic/structs.rs index 9a5260c..01dd8c8 100644 --- a/ic10emu/src/vm/object/generic/structs.rs +++ b/ic10emu/src/vm/object/generic/structs.rs @@ -4,10 +4,10 @@ use crate::{network::Connection, vm::{ enums::script_enums::LogicType, object::{ macros::ObjectInterface, templates::{DeviceInfo, ItemInfo}, traits::*, LogicField, Name, ObjectID, Slot, - }, + }, VM, }}; use macro_rules_attribute::derive; -use std::collections::BTreeMap; +use std::{collections::BTreeMap, rc::Rc}; #[derive(ObjectInterface!, GWStructure!)] #[custom(implements(Object { Structure }))] @@ -18,6 +18,8 @@ pub struct Generic { pub prefab: Name, #[custom(object_name)] pub name: Name, + #[custom(object_vm_ref)] + pub vm: Option>, pub small_grid: bool, } @@ -30,6 +32,8 @@ pub struct GenericStorage { pub prefab: Name, #[custom(object_name)] pub name: Name, + #[custom(object_vm_ref)] + pub vm: Option>, pub small_grid: bool, pub slots: Vec, } @@ -43,6 +47,8 @@ pub struct GenericLogicable { pub prefab: Name, #[custom(object_name)] pub name: Name, + #[custom(object_vm_ref)] + pub vm: Option>, pub small_grid: bool, pub slots: Vec, pub fields: BTreeMap, @@ -58,6 +64,8 @@ pub struct GenericLogicableDevice { pub prefab: Name, #[custom(object_name)] pub name: Name, + #[custom(object_vm_ref)] + pub vm: Option>, pub small_grid: bool, pub slots: Vec, pub fields: BTreeMap, @@ -76,6 +84,8 @@ pub struct GenericLogicableDeviceMemoryReadable { pub prefab: Name, #[custom(object_name)] pub name: Name, + #[custom(object_vm_ref)] + pub vm: Option>, pub small_grid: bool, pub slots: Vec, pub fields: BTreeMap, @@ -95,6 +105,8 @@ pub struct GenericLogicableDeviceMemoryReadWriteable { pub prefab: Name, #[custom(object_name)] pub name: Name, + #[custom(object_vm_ref)] + pub vm: Option>, pub small_grid: bool, pub slots: Vec, pub fields: BTreeMap, @@ -114,6 +126,8 @@ pub struct GenericItem { pub prefab: Name, #[custom(object_name)] pub name: Name, + #[custom(object_vm_ref)] + pub vm: Option>, pub item_info: ItemInfo, pub parent_slot: Option, } @@ -127,6 +141,8 @@ pub struct GenericItemStorage { pub prefab: Name, #[custom(object_name)] pub name: Name, + #[custom(object_vm_ref)] + pub vm: Option>, pub item_info: ItemInfo, pub parent_slot: Option, pub slots: Vec, @@ -141,6 +157,8 @@ pub struct GenericItemLogicable { pub prefab: Name, #[custom(object_name)] pub name: Name, + #[custom(object_vm_ref)] + pub vm: Option>, pub item_info: ItemInfo, pub parent_slot: Option, pub slots: Vec, @@ -157,6 +175,8 @@ pub struct GenericItemLogicableMemoryReadable { pub prefab: Name, #[custom(object_name)] pub name: Name, + #[custom(object_vm_ref)] + pub vm: Option>, pub item_info: ItemInfo, pub parent_slot: Option, pub slots: Vec, @@ -174,6 +194,8 @@ pub struct GenericItemLogicableMemoryReadWriteable { pub prefab: Name, #[custom(object_name)] pub name: Name, + #[custom(object_vm_ref)] + pub vm: Option>, pub item_info: ItemInfo, pub parent_slot: Option, pub slots: Vec, diff --git a/ic10emu/src/vm/object/generic/traits.rs b/ic10emu/src/vm/object/generic/traits.rs index 84b6789..a991f42 100644 --- a/ic10emu/src/vm/object/generic/traits.rs +++ b/ic10emu/src/vm/object/generic/traits.rs @@ -53,7 +53,7 @@ impl Storage for T { pub trait GWLogicable: Storage { fn fields(&self) -> &BTreeMap; fn fields_mut(&mut self) -> &mut BTreeMap; - fn modes(&self) -> Option<&BTreeMap>; + fn known_modes(&self) -> Option<&BTreeMap>; } impl Logicable for T { @@ -148,8 +148,13 @@ impl Logicable for T { fn valid_logic_types(&self) -> Vec { self.fields().keys().copied().collect() } - fn known_modes(&self) -> Option> { - self.modes().map(|modes| modes.iter().collect()) + fn known_modes(&self) -> Option> { + self.known_modes().map(|modes| { + modes + .iter() + .map(|(mode, name)| (*mode, name.clone())) + .collect() + }) } } @@ -171,7 +176,7 @@ impl MemoryReadable for T { Ok(self.memory()[index as usize]) } } - fn get_memory_slice(&self) -> &[f64] { + fn get_memory_slice(&self) -> &[f64] { self.memory() } } diff --git a/ic10emu/src/vm/object/macros.rs b/ic10emu/src/vm/object/macros.rs index ce9a691..bc9ba1e 100644 --- a/ic10emu/src/vm/object/macros.rs +++ b/ic10emu/src/vm/object/macros.rs @@ -14,6 +14,8 @@ macro_rules! object_trait { 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 get_vm(&self) -> Option<&std::rc::Rc>; + fn set_vm(&mut self, vm: std::rc::Rc); fn type_name(&self) -> &str; fn as_object(&self) -> &dyn $trait_name; fn as_mut_object(&mut self) -> &mut dyn $trait_name; @@ -71,14 +73,25 @@ macro_rules! object_trait { pub(crate) use object_trait; +/// use macro_rules_attribute::derive to apply this macro to a struct +/// +/// use `#[custom(object_id)]`, `#[custom(object_prefab)]`, `#[custom(object_name)]`, and `#[custom(object_vm_ref)]` +/// to tag struct fields appropriately +/// +/// the tags for `id`, `prefab`, and `name` may appear in any order but `vm_ref` must come last +/// +/// - `id` must be `crate::vm::object::ObjectID` +/// - `prefab` and `name` must be `crate::vm::object::Name` +/// - `vm_ref` must be `Option>` macro_rules! ObjectInterface { { - @body_id_prefab_name + @body_final @trt $trait_name:ident; $struct:ident; @impls $($trt:path),*; @id $id_field:ident: $id_typ:ty; @prefab $prefab_field:ident: $prefab_typ:ty; @name $name_field:ident: $name_typ:ty; + @vm_ref $vm_ref_field:ident: $vm_ref_typ:ty; } => { impl $trait_name for $struct { @@ -106,6 +119,14 @@ macro_rules! ObjectInterface { &mut self.$name_field } + fn get_vm(&self) -> Option<&std::rc::Rc> { + self.$vm_ref_field.as_ref() + } + + fn set_vm(&mut self, vm: std::rc::Rc) { + self.$vm_ref_field = Some(vm); + } + fn type_name(&self) -> &str { std::any::type_name::() } @@ -135,301 +156,117 @@ macro_rules! ObjectInterface { } }; { - @body_id_name + @body_final @trt $trait_name:ident; $struct:ident; @impls $($trt:path),*; @id $id_field:ident: $id_typ:ty; @name $name_field:ident: $name_typ:ty; - #[custom(object_prefab)] - $(#[$prefab_attr:meta])* - $prefab_viz:vis $prefab_field:ident: $prefab_typ:ty, - $( $rest:tt )* - - } => { - $crate::vm::object::macros::ObjectInterface!{ - @body_id_prefab_name - @trt $trait_name; $struct; - @impls $($trt),*; - @id $id_field: $id_typ; - @prefab $prefab_field: $prefab_typ; - @name $name_field: $name_typ; - } - }; - { - @body_id_name - @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; - @id $id_field:ident: $id_typ:ty; - @name $name_field:ident: $name_typ:ty; - $(#[#field:meta])* - $field_viz:vis - $field_name:ident : $field_ty:ty, - $( $rest:tt )* - - } => { - $crate::vm::object::macros::ObjectInterface!{ - @body_id_name - @trt $trait_name; $struct; - @impls $($trt),*; - @id $id_field: $id_typ; - @name $name_field: $name_typ; - $( $rest )* - } - }; - { - @body_id_prefab - @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; - @id $id_field:ident: $id_typ:ty; @prefab $prefab_field:ident: $prefab_typ:ty; - #[custom(object_name)] - $(#[$name_attr:meta])* - $name_viz:vis $name_field:ident: $name_typ:ty, - $( $rest:tt )* - + @vm_ref $vm_ref_field:ident: $vm_ref_typ:ty; } => { $crate::vm::object::macros::ObjectInterface!{ - @body_id_prefab_name + @body_final @trt $trait_name; $struct; @impls $($trt),*; @id $id_field: $id_typ; @prefab $prefab_field: $prefab_typ; @name $name_field: $name_typ; + @vm_ref $vm_ref_field: $vm_ref_typ; } }; { - @body_id_prefab - @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; - @id $id_field:ident: $id_typ:ty; - @prefab $prefab_field:ident: $prefab_typ:ty; - $(#[#field:meta])* - $field_viz:vis - $field_name:ident : $field_ty:ty, - $( $rest:tt )* - - } => { - $crate::vm::object::macros::ObjectInterface!{ - @body_id_prefab - @trt $trait_name; $struct; - @impls $($trt),*; - @id $id_field: $id_typ; - @prefab $prefab_field: $prefab_typ; - $( $rest )* - } - }; - { - @body_prefab_name + @body_final @trt $trait_name:ident; $struct:ident; @impls $($trt:path),*; @prefab $prefab_field:ident: $prefab_typ:ty; @name $name_field:ident: $name_typ:ty; - #[custom(object_id)] - $(#[$id_attr:meta])* - $id_viz:vis $id_field:ident: $id_typ:ty, - $( $rest:tt )* - - } => { - $crate::vm::object::macros::ObjectInterface!{ - @body_id_prefab_name - @trt $trait_name; $struct; - @impls $($trt),*; - @prefab $prefab_field: $prefab_typ; - @name $name_field: $name_typ; - } - }; - { - @body_prefab_name - @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; - @prefab $prefab_field:ident: $prefab_typ:ty; - @name $name_field:ident: $name_typ:ty; - $(#[#field:meta])* - $field_viz:vis - $field_name:ident : $field_ty:ty, - $( $rest:tt )* - - } => { - $crate::vm::object::macros::ObjectInterface!{ - @body_prefab_name - @trt $trait_name; $struct; - @impls $($trt),*; - @prefab $prefab_field: $prefab_typ; - @name $name_field: $name_typ; - $( $rest )* - } - }; - { - @body_name - @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; - @name $name_field:ident: $name_typ:ty; - #[custom(object_prefab)] - $(#[$prefab_attr:meta])* - $prefab_viz:vis $prefab_field:ident: $prefab_typ:ty, - $( $rest:tt )* - - } => { - $crate::vm::object::macros::ObjectInterface!{ - @body_prefab_name - @trt $trait_name; $struct; - @impls $($trt),*; - @prefab $prefab_field: $prefab_typ; - @name $name_field: $name_typ; - $( $rest )* - } - }; - { - @body_name - @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; - @name $name_field:ident: $name_typ:ty; - #[custom(object_id)] - $(#[$id_attr:meta])* - $id_viz:vis $id_field:ident: $id_typ:ty, - $( $rest:tt )* - - } => { - $crate::vm::object::macros::ObjectInterface!{ - @body_id_name - @trt $trait_name; $struct; - @impls $($trt),*; - @id $id_field: $id_typ; - @name $name_field: $name_typ; - $( $rest )* - } - }; - { - @body_name - @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; - @name $name_field:ident: $name_typ:ty; - $(#[#field:meta])* - $field_viz:vis - $field_name:ident : $field_ty:ty, - $( $rest:tt )* - - } => { - $crate::vm::object::macros::ObjectInterface!{ - @body_name - @trt $trait_name; $struct; - @impls $($trt),*; - @name $name_field: $name_typ; - $( $rest )* - } - }; - { - @body_id - @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; @id $id_field:ident: $id_typ:ty; - #[custom(object_name)] - $(#[$name_attr:meta])* - $name_viz:vis $name_field:ident: $name_typ:ty, - $( $rest:tt )* + @vm_ref $vm_ref_field:ident: $vm_ref_typ:ty; } => { $crate::vm::object::macros::ObjectInterface!{ - @body_id_name + @body_final @trt $trait_name; $struct; @impls $($trt),*; @id $id_field: $id_typ; - @name $name_field: $name_typ; - $( $rest )* - } - }; - { - @body_id - @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; - @id $id_field:ident: $id_typ:ty; - #[custom(object_prefab)] - $(#[$prefab_attr:meta])* - $prefab_viz:vis $prefab_field:ident: $prefab_typ:ty, - $( $rest:tt )* - } => { - $crate::vm::object::macros::ObjectInterface!{ - @body_id_prefab - @trt $trait_name; $struct; - @impls $($trt),*; - @id $id_field: $id_typ; - @prefab $prefab_field: $prefab_typ; - $( $rest )* - } - }; - { - @body_id - @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; - @id $id_field:ident: $id_typ:ty; - $(#[#field:meta])* - $field_viz:vis - $field_name:ident : $field_ty:ty, - $( $rest:tt )* - } => { - $crate::vm::object::macros::ObjectInterface!{ - @body_id - @trt $trait_name; $struct; - @impls $($trt),*; - @id $id_field: $id_typ; - $( $rest )* - } - }; - { - @body_prefab - @trt $trait_name:ident; $struct:ident; - @impls $($trt:path),*; - @prefab $prefab_field:ident: $prefab_typ:ty; - #[custom(object_name)] - $(#[$name_attr:meta])* - $name_viz:vis $name_field:ident: $name_typ:ty, - $( $rest:tt )* - - } => { - $crate::vm::object::macros::ObjectInterface!{ - @body_prefab_name - @trt $trait_name; $struct; - @impls $($trt),*; @prefab $prefab_field: $prefab_typ; @name $name_field: $name_typ; - $( $rest )* + @vm_ref $vm_ref_field: $vm_ref_typ; } }; { - @body_prefab + @body_final @trt $trait_name:ident; $struct:ident; @impls $($trt:path),*; @prefab $prefab_field:ident: $prefab_typ:ty; - #[custom(object_id)] - $(#[$id_attr:meta])* - $id_viz:vis $id_field:ident: $id_typ:ty, - $( $rest:tt )* - + @id $id_field:ident: $id_typ:ty; + @name $name_field:ident: $name_typ:ty; + @vm_ref $vm_ref_field:ident: $vm_ref_typ:ty; } => { $crate::vm::object::macros::ObjectInterface!{ - @body_id_prefab + @body_final @trt $trait_name; $struct; @impls $($trt),*; @id $id_field: $id_typ; @prefab $prefab_field: $prefab_typ; - $( $rest )* + @name $name_field: $name_typ; + @vm_ref $vm_ref_field: $vm_ref_typ; } }; { - @body_prefab + @body_final @trt $trait_name:ident; $struct:ident; @impls $($trt:path),*; + @name $name_field:ident: $name_typ:ty; @prefab $prefab_field:ident: $prefab_typ:ty; - $(#[#field:meta])* - $field_viz:vis - $field_name:ident : $field_ty:ty, + @id $id_field:ident: $id_typ:ty; + @vm_ref $vm_ref_field:ident: $vm_ref_typ:ty; + } => { + $crate::vm::object::macros::ObjectInterface!{ + @body_final + @trt $trait_name; $struct; + @impls $($trt),*; + @id $id_field: $id_typ; + @prefab $prefab_field: $prefab_typ; + @name $name_field: $name_typ; + @vm_ref $vm_ref_field: $vm_ref_typ; + } + }; + { + @body_final + @trt $trait_name:ident; $struct:ident; + @impls $($trt:path),*; + @name $name_field:ident: $name_typ:ty; + @id $id_field:ident: $id_typ:ty; + @prefab $prefab_field:ident: $prefab_typ:ty; + @vm_ref $vm_ref_field:ident: $vm_ref_typ:ty; + } => { + $crate::vm::object::macros::ObjectInterface!{ + @body_final + @trt $trait_name; $struct; + @impls $($trt),*; + @id $id_field: $id_typ; + @prefab $prefab_field: $prefab_typ; + @name $name_field: $name_typ; + @vm_ref $vm_ref_field: $vm_ref_typ; + } + };{ + @body + @trt $trait_name:ident; $struct:ident; + @impls $($trt:path),*; + @tags { + $(@$tag:tt $tag_field:ident: $tag_typ:ty;)* + }; + #[custom(object_vm_ref)] + $(#[$vm_ref_attr:meta])* + $vm_ref_viz:vis $vm_ref_field:ident: $vm_ref_typ:ty, $( $rest:tt )* } => { $crate::vm::object::macros::ObjectInterface!{ - @body_prefab + @body @trt $trait_name; $struct; @impls $($trt),*; - @prefab $prefab_field: $prefab_typ; + @tags {$(@$tag $tag_field: $tag_typ;)* @vm_ref $vm_ref_field: $vm_ref_typ;}; $( $rest )* } }; @@ -437,6 +274,9 @@ macro_rules! ObjectInterface { @body @trt $trait_name:ident; $struct:ident; @impls $($trt:path),*; + @tags { + $(@$tag:tt $tag_field:ident: $tag_typ:ty;)* + }; #[custom(object_name)] $(#[$name_attr:meta])* $name_viz:vis $name_field:ident: $name_typ:ty, @@ -444,10 +284,10 @@ macro_rules! ObjectInterface { } => { $crate::vm::object::macros::ObjectInterface!{ - @body_name + @body @trt $trait_name; $struct; @impls $($trt),*; - @name $name_field: $name_typ; + @tags {$(@$tag $tag_field: $tag_typ;)* @name $name_field: $name_typ;}; $( $rest )* } }; @@ -455,6 +295,9 @@ macro_rules! ObjectInterface { @body @trt $trait_name:ident; $struct:ident; @impls $($trt:path),*; + @tags { + $(@$tag:tt $tag_field:ident: $tag_typ:ty;)* + }; #[custom(object_prefab)] $(#[$prefab_attr:meta])* $prefab_viz:vis $prefab_field:ident: $prefab_typ:ty, @@ -462,10 +305,10 @@ macro_rules! ObjectInterface { } => { $crate::vm::object::macros::ObjectInterface!{ - @body_prefab + @body @trt $trait_name; $struct; @impls $($trt),*; - @prefab $prefab_field: $prefab_typ; + @tags {$(@$tag $tag_field: $tag_typ;)* @prefab $prefab_field: $prefab_typ;}; $( $rest )* } }; @@ -473,6 +316,9 @@ macro_rules! ObjectInterface { @body @trt $trait_name:ident; $struct:ident; @impls $($trt:path),*; + @tags { + $(@$tag:tt $tag_field:ident: $tag_typ:ty;)* + }; #[custom(object_id)] $(#[$id_attr:meta])* $id_viz:vis $id_field:ident: $id_typ:ty, @@ -480,10 +326,10 @@ macro_rules! ObjectInterface { } => { $crate::vm::object::macros::ObjectInterface!{ - @body_id + @body @trt $trait_name; $struct; @impls $($trt),*; - @id $id_field: $id_typ; + @tags {$(@$tag $tag_field: $tag_typ;)* @id $id_field: $id_typ;}; $( $rest )* } }; @@ -491,7 +337,10 @@ macro_rules! ObjectInterface { @body @trt $trait_name:ident; $struct:ident; @impls $($trt:path),*; - $(#[#field:meta])* + @tags { + $(@$tag:tt $tag_field:ident: $tag_typ:ty;)* + }; + $(#[$field:meta])* $field_viz:vis $field_name:ident : $field_ty:ty, $( $rest:tt )* @@ -501,9 +350,27 @@ macro_rules! ObjectInterface { @body @trt $trait_name; $struct; @impls $($trt),*; + @tags {$(@$tag $tag_field: $tag_typ;)*}; $( $rest )* } }; + { + @body + @trt $trait_name:ident; $struct:ident; + @impls $($trt:path),*; + @tags { + $(@$tag:tt $tag_field:ident: $tag_typ:ty;)* + }; + } => { + $crate::vm::object::macros::ObjectInterface!{ + @body_final + @trt $trait_name; $struct; + @impls $($trt),*; + $( + @$tag $tag_field: $tag_typ; + )* + } + }; { #[custom(implements($trait_name:ident {$($trt:path),*}))] $( #[$attr:meta] )* @@ -515,6 +382,7 @@ macro_rules! ObjectInterface { @body @trt $trait_name; $struct; @impls $($trt),*; + @tags {}; $( $body )* } }; diff --git a/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs b/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs index 8496eea..bc40db8 100644 --- a/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs +++ b/ic10emu/src/vm/object/stationpedia/structs/integrated_circuit.rs @@ -1,10 +1,11 @@ use crate::{ errors::{ICError, LineError}, grammar, + interpreter::ICState, vm::{ enums::{ basic_enums::{Class as SlotClass, GasType, SortingClass}, - script_enums::LogicType, + script_enums::{LogicSlotType, LogicType}, }, instructions::{ enums::InstructionOp, @@ -13,11 +14,10 @@ use crate::{ Instruction, }, object::{ - errors::MemoryError, - generic::{macros::GWLogicable, traits::GWLogicable}, + errors::{LogicError, MemoryError}, macros::ObjectInterface, traits::*, - LogicField, Name, ObjectID, Slot, + LogicField, MemoryAccess, Name, ObjectID, Slot, }, VM, }, @@ -25,7 +25,10 @@ use crate::{ use itertools::Itertools; use macro_rules_attribute::derive; use serde_derive::{Deserialize, Serialize}; -use std::collections::{BTreeMap, HashSet}; +use std::{ + collections::{BTreeMap, HashSet}, + rc::Rc, +}; use ICError::*; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -139,20 +142,10 @@ impl Program { } } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum ICState { - Start, - Running, - Yield, - Sleep(time::OffsetDateTime, f64), - HasCaughtFire, - Error(LineError), -} - static RETURN_ADDRESS_INDEX: usize = 17; static STACK_POINTER_INDEX: usize = 16; -#[derive(ObjectInterface!, GWLogicable!)] +#[derive(ObjectInterface!)] #[custom(implements(Object { Item, Storage, Logicable, MemoryReadable, MemoryWritable }))] pub struct ItemIntegratedCircuit10 { #[custom(object_id)] @@ -161,6 +154,8 @@ pub struct ItemIntegratedCircuit10 { pub prefab: Name, #[custom(object_name)] pub name: Name, + #[custom(object_vm_ref)] + pub vm: Option>, pub fields: BTreeMap, pub memory: [f64; 512], pub parent_slot: Option, @@ -218,13 +213,86 @@ impl Storage for ItemIntegratedCircuit10 { fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot> { None } - fn get_slots(&self) -> &[Slot] { + fn get_slots(&self) -> &[Slot] { &[] } - fn get_slots_mut(&mut self) -> &mut[Slot] { + fn get_slots_mut(&mut self) -> &mut [Slot] { &mut [] } } +impl Logicable for ItemIntegratedCircuit10 { + fn prefab_hash(&self) -> i32 { + self.get_prefab().hash + } + fn name_hash(&self) -> i32 { + self.get_name().hash + } + fn is_logic_readable(&self) -> bool { + true + } + fn is_logic_writeable(&self) -> bool { + true + } + fn can_logic_read(&self, lt: LogicType) -> bool { + self.fields + .get(<) + .map(|field| { + matches!( + field.field_type, + MemoryAccess::Read | MemoryAccess::ReadWrite + ) + }) + .unwrap_or(false) + } + fn can_logic_write(&self, lt: LogicType) -> bool { + self.fields + .get(<) + .map(|field| { + matches!( + field.field_type, + MemoryAccess::Write | MemoryAccess::ReadWrite + ) + }) + .unwrap_or(false) + } + fn get_logic(&self, lt: LogicType) -> Result { + self.fields + .get(<) + .and_then(|field| match field.field_type { + MemoryAccess::Read | MemoryAccess::ReadWrite => Some(field.value), + _ => None, + }) + .ok_or(LogicError::CantRead(lt)) + } + fn set_logic(&mut self, lt: LogicType, value: f64, force: bool) -> Result<(), LogicError> { + self.fields + .get_mut(<) + .ok_or(LogicError::CantWrite(lt)) + .and_then(|field| match field.field_type { + MemoryAccess::Write | MemoryAccess::ReadWrite => { + field.value = value; + Ok(()) + } + _ if force => { + field.value = value; + Ok(()) + } + _ => Err(LogicError::CantWrite(lt)), + }) + } + fn can_slot_logic_read(&self, slt: LogicSlotType, index: f64) -> bool { + false + } + fn get_slot_logic(&self, slt: LogicSlotType, index: f64, _vm: &VM) -> Result { + return Err(LogicError::SlotIndexOutOfRange(index, self.slots_count())); + } + fn valid_logic_types(&self) -> Vec { + self.fields.keys().copied().collect() + } + fn known_modes(&self) -> Option> { + None + } +} impl MemoryReadable for ItemIntegratedCircuit10 { fn memory_size(&self) -> usize { @@ -239,7 +307,7 @@ impl MemoryReadable for ItemIntegratedCircuit10 { Ok(self.memory[index as usize]) } } - fn get_memory_slice(&self) -> &[f64] { + fn get_memory_slice(&self) -> &[f64] { &self.memory } } @@ -280,9 +348,14 @@ impl SourceCode for ItemIntegratedCircuit10 { } impl IntegratedCircuit for ItemIntegratedCircuit10 { - fn get_circuit_holder(&self, vm: &VM) -> Option { - // FIXME: implement correctly - self.get_parent_slot().map(|parent_slot| parent_slot.parent) + fn get_circuit_holder(&self, vm: &Rc) -> Option { + self.get_parent_slot() + .map(|parent_slot| { + vm.get_object(parent_slot.parent) + .map(|obj| obj.borrow().as_circuit_holder()) + .flatten() + }) + .flatten() } fn get_instruction_pointer(&self) -> f64 { self.ip as f64 @@ -338,9 +411,9 @@ impl IntegratedCircuit for ItemIntegratedCircuit10 { fn push_stack(&mut self, val: f64) -> Result { let sp = (self.registers[STACK_POINTER_INDEX].round()) as i32; if sp < 0 { - Err(ICError::StackUnderflow) + Err(MemoryError::StackUnderflow(sp, self.memory.len()).into()) } else if sp as usize >= self.memory.len() { - Err(ICError::StackOverflow) + Err(MemoryError::StackOverflow(sp, self.memory.len()).into()) } else { let last = self.memory[sp as usize]; self.memory[sp as usize] = val; @@ -352,9 +425,9 @@ impl IntegratedCircuit for ItemIntegratedCircuit10 { self.registers[STACK_POINTER_INDEX] -= 1.0; let sp = (self.registers[STACK_POINTER_INDEX].round()) as i32; if sp < 0 { - Err(ICError::StackUnderflow) + Err(MemoryError::StackUnderflow(sp, self.memory.len()).into()) } else if sp as usize >= self.memory.len() { - Err(ICError::StackOverflow) + Err(MemoryError::StackOverflow(sp, self.memory.len()).into()) } else { let last = self.memory[sp as usize]; Ok(last) @@ -363,9 +436,9 @@ impl IntegratedCircuit for ItemIntegratedCircuit10 { fn peek_stack(&self) -> Result { let sp = (self.registers[STACK_POINTER_INDEX] - 1.0).round() as i32; if sp < 0 { - Err(ICError::StackUnderflow) + Err(MemoryError::StackUnderflow(sp, self.memory.len()).into()) } else if sp as usize >= self.memory.len() { - Err(ICError::StackOverflow) + Err(MemoryError::StackOverflow(sp, self.memory.len()).into()) } else { let last = self.memory[sp as usize]; Ok(last) @@ -1325,7 +1398,6 @@ impl BdseInstruction for ItemIntegratedCircuit10 { } } - // impl BdsealInstruction for ItemIntegratedCircuit10 { // /// bdseal d? a(r?|num) // fn execute_bdseal(&mut self, vm: &VM, d: &Operand, a: &Operand) -> Result<(), ICError>; diff --git a/ic10emu/src/vm/object/templates.rs b/ic10emu/src/vm/object/templates.rs index 19abf69..f564207 100644 --- a/ic10emu/src/vm/object/templates.rs +++ b/ic10emu/src/vm/object/templates.rs @@ -203,6 +203,7 @@ impl ObjectTemplate { id, prefab: Name::from_prefab_name(&s.prefab.prefab_name), name: Name::new(&s.prefab.name), + vm: None, small_grid: s.structure.small_grid, }, vm.clone(), @@ -212,6 +213,7 @@ impl ObjectTemplate { id, prefab: Name::from_prefab_name(&s.prefab.prefab_name), name: Name::new(&s.prefab.name), + vm: None, small_grid: s.structure.small_grid, slots: s .slots @@ -235,6 +237,7 @@ impl ObjectTemplate { id, prefab: Name::from_prefab_name(&s.prefab.prefab_name), name: Name::new(&s.prefab.name), + vm: None, small_grid: s.structure.small_grid, slots: s .slots @@ -314,6 +317,7 @@ impl ObjectTemplate { id, prefab: Name::from_prefab_name(&s.prefab.prefab_name), name: Name::new(&s.prefab.name), + vm: None, small_grid: s.structure.small_grid, slots: s .slots @@ -414,6 +418,7 @@ impl ObjectTemplate { id, prefab: Name::from_prefab_name(&s.prefab.prefab_name), name: Name::new(&s.prefab.name), + vm: None, small_grid: s.structure.small_grid, slots: s .slots @@ -521,6 +526,7 @@ impl ObjectTemplate { id, prefab: Name::from_prefab_name(&s.prefab.prefab_name), name: Name::new(&s.prefab.name), + vm: None, small_grid: s.structure.small_grid, slots: s .slots @@ -623,6 +629,7 @@ impl ObjectTemplate { id, prefab: Name::from_prefab_name(&i.prefab.prefab_name), name: Name::new(&i.prefab.name), + vm: None, item_info: i.item.clone(), parent_slot: None, }, @@ -633,6 +640,7 @@ impl ObjectTemplate { id, prefab: Name::from_prefab_name(&i.prefab.prefab_name), name: Name::new(&i.prefab.name), + vm: None, item_info: i.item.clone(), parent_slot: None, slots: i @@ -657,6 +665,7 @@ impl ObjectTemplate { id, prefab: Name::from_prefab_name(&i.prefab.prefab_name), name: Name::new(&i.prefab.name), + vm: None, item_info: i.item.clone(), parent_slot: None, slots: i @@ -738,6 +747,7 @@ impl ObjectTemplate { id, prefab: Name::from_prefab_name(&i.prefab.prefab_name), name: Name::new(&i.prefab.name), + vm: None, item_info: i.item.clone(), parent_slot: None, slots: i @@ -824,6 +834,7 @@ impl ObjectTemplate { id, prefab: Name::from_prefab_name(&i.prefab.prefab_name), name: Name::new(&i.prefab.name), + vm: None, item_info: i.item.clone(), parent_slot: None, slots: i @@ -1308,7 +1319,7 @@ impl From> for LogicInfo { .iter() .filter_map(|lt| match logic.get_logic(*lt) { Ok(val) => Some((*lt, val)), - _ => None + _ => None, }) .collect(), ), @@ -1377,9 +1388,15 @@ pub struct DeviceInfo { impl From> for DeviceInfo { fn from(device: DeviceRef) -> Self { DeviceInfo { - connection_list: device.connection_list().iter().map(|conn| conn.to_info()).collect(), + connection_list: device + .connection_list() + .iter() + .map(|conn| conn.to_info()) + .collect(), device_pins_length: device.device_pins().map(|pins| pins.len()), - device_pins: device.device_pins().map(|pins| pins.iter().copied().collect()), + device_pins: device + .device_pins() + .map(|pins| pins.iter().copied().collect()), has_reagents: device.has_reagents(), has_lock_state: device.has_lock_state(), has_mode_state: device.has_mode_state(), diff --git a/ic10emu/src/vm/object/traits.rs b/ic10emu/src/vm/object/traits.rs index b209fb1..264b37e 100644 --- a/ic10emu/src/vm/object/traits.rs +++ b/ic10emu/src/vm/object/traits.rs @@ -15,7 +15,7 @@ use crate::{ VM, } }; -use std::{collections::BTreeMap, fmt::Debug}; +use std::{collections::BTreeMap, fmt::Debug, rc::Rc}; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub struct ParentSlotInfo { @@ -99,7 +99,7 @@ tag_object_traits! { } pub trait IntegratedCircuit: Logicable + MemoryWritable + SourceCode + Item { - fn get_circuit_holder(&self, vm: &VM) -> Option; + fn get_circuit_holder(&self, vm: &Rc) -> Option; fn get_instruction_pointer(&self) -> f64; fn set_next_instruction(&mut self, next_instruction: f64); fn set_next_instruction_relative(&mut self, offset: f64) {