refactor(vm): cleanup borrow usage, impl slot logic
This commit is contained in:
@@ -1,907 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
errors::ICError,
|
|
||||||
interpreter::ICState,
|
|
||||||
network::{CableConnectionType, Connection},
|
|
||||||
vm::enums::{
|
|
||||||
basic_enums::{Class as SlotClass, SortingClass},
|
|
||||||
script_enums::{LogicReagentMode as ReagentMode, LogicSlotType, LogicType},
|
|
||||||
},
|
|
||||||
vm::VM,
|
|
||||||
};
|
|
||||||
use std::{collections::BTreeMap, ops::Deref};
|
|
||||||
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
use serde_derive::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
pub enum MemoryAccess {
|
|
||||||
Read,
|
|
||||||
Write,
|
|
||||||
ReadWrite,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct LogicField {
|
|
||||||
pub field_type: MemoryAccess,
|
|
||||||
pub value: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct SlotOccupant {
|
|
||||||
pub id: u32,
|
|
||||||
pub prefab_hash: i32,
|
|
||||||
pub quantity: u32,
|
|
||||||
pub max_quantity: u32,
|
|
||||||
pub sorting_class: SortingClass,
|
|
||||||
pub damage: f64,
|
|
||||||
fields: BTreeMap<LogicSlotType, LogicField>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SlotOccupant {
|
|
||||||
pub fn from_template<F>(template: SlotOccupantTemplate, id_fn: F) -> Self
|
|
||||||
where
|
|
||||||
F: FnOnce() -> u32,
|
|
||||||
{
|
|
||||||
let mut fields = template.fields;
|
|
||||||
SlotOccupant {
|
|
||||||
id: template.id.unwrap_or_else(id_fn),
|
|
||||||
prefab_hash: fields
|
|
||||||
.remove(&LogicSlotType::PrefabHash)
|
|
||||||
.map(|field| field.value as i32)
|
|
||||||
.unwrap_or(0),
|
|
||||||
quantity: fields
|
|
||||||
.remove(&LogicSlotType::Quantity)
|
|
||||||
.map(|field| field.value as u32)
|
|
||||||
.unwrap_or(1),
|
|
||||||
max_quantity: fields
|
|
||||||
.remove(&LogicSlotType::MaxQuantity)
|
|
||||||
.map(|field| field.value as u32)
|
|
||||||
.unwrap_or(1),
|
|
||||||
damage: fields
|
|
||||||
.remove(&LogicSlotType::Damage)
|
|
||||||
.map(|field| field.value)
|
|
||||||
.unwrap_or(0.0),
|
|
||||||
sorting_class: fields
|
|
||||||
.remove(&LogicSlotType::SortingClass)
|
|
||||||
.map(|field| SortingClass::from_repr(field.value as u8))
|
|
||||||
.flatten()
|
|
||||||
.unwrap_or(SortingClass::Default),
|
|
||||||
fields,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct SlotOccupantTemplate {
|
|
||||||
pub id: Option<u32>,
|
|
||||||
pub fields: BTreeMap<LogicSlotType, LogicField>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SlotOccupant {
|
|
||||||
pub fn new(id: u32, prefab_hash: i32) -> Self {
|
|
||||||
SlotOccupant {
|
|
||||||
id,
|
|
||||||
prefab_hash,
|
|
||||||
quantity: 1,
|
|
||||||
max_quantity: 1,
|
|
||||||
damage: 0.0,
|
|
||||||
sorting_class: SortingClass::Default,
|
|
||||||
fields: BTreeMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// chainable constructor
|
|
||||||
pub fn with_quantity(mut self, quantity: u32) -> Self {
|
|
||||||
self.quantity = quantity;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// chainable constructor
|
|
||||||
pub fn with_max_quantity(mut self, max_quantity: u32) -> Self {
|
|
||||||
self.max_quantity = max_quantity;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// chainable constructor
|
|
||||||
pub fn with_damage(mut self, damage: f64) -> Self {
|
|
||||||
self.damage = damage;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// chainable constructor
|
|
||||||
pub fn with_fields(mut self, fields: BTreeMap<LogicSlotType, LogicField>) -> Self {
|
|
||||||
self.fields.extend(fields);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// chainable constructor
|
|
||||||
pub fn get_fields(&self) -> BTreeMap<LogicSlotType, LogicField> {
|
|
||||||
let mut copy = self.fields.clone();
|
|
||||||
copy.insert(
|
|
||||||
LogicSlotType::PrefabHash,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: self.prefab_hash as f64,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy.insert(
|
|
||||||
LogicSlotType::SortingClass,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: self.sorting_class as u32 as f64,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy.insert(
|
|
||||||
LogicSlotType::Quantity,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: self.quantity as f64,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy.insert(
|
|
||||||
LogicSlotType::MaxQuantity,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: self.max_quantity as f64,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy.insert(
|
|
||||||
LogicSlotType::Damage,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: self.damage,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_field(&mut self, typ: LogicSlotType, val: f64, force: bool) -> Result<(), ICError> {
|
|
||||||
if (typ == LogicSlotType::Quantity) && force {
|
|
||||||
self.quantity = val as u32;
|
|
||||||
Ok(())
|
|
||||||
} else if (typ == LogicSlotType::MaxQuantity) && force {
|
|
||||||
self.max_quantity = val as u32;
|
|
||||||
Ok(())
|
|
||||||
} else if (typ == LogicSlotType::Damage) && force {
|
|
||||||
self.damage = val;
|
|
||||||
Ok(())
|
|
||||||
} else if let Some(logic) = self.fields.get_mut(&typ) {
|
|
||||||
match logic.field_type {
|
|
||||||
MemoryAccess::ReadWrite | MemoryAccess::Write => {
|
|
||||||
logic.value = val;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
if force {
|
|
||||||
logic.value = val;
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(ICError::ReadOnlyField(typ.to_string()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if force {
|
|
||||||
self.fields.insert(
|
|
||||||
typ,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::ReadWrite,
|
|
||||||
value: val,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(ICError::ReadOnlyField(typ.to_string()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn can_logic_read(&self, field: LogicSlotType) -> bool {
|
|
||||||
if let Some(logic) = self.fields.get(&field) {
|
|
||||||
matches!(
|
|
||||||
logic.field_type,
|
|
||||||
MemoryAccess::Read | MemoryAccess::ReadWrite
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn can_logic_write(&self, field: LogicSlotType) -> bool {
|
|
||||||
if let Some(logic) = self.fields.get(&field) {
|
|
||||||
matches!(
|
|
||||||
logic.field_type,
|
|
||||||
MemoryAccess::Write | MemoryAccess::ReadWrite
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct Slot {
|
|
||||||
pub typ: SlotClass,
|
|
||||||
pub occupant: Option<SlotOccupant>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct SlotTemplate {
|
|
||||||
pub typ: SlotClass,
|
|
||||||
pub occupant: Option<SlotOccupantTemplate>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Slot {
|
|
||||||
pub fn new(typ: SlotClass) -> Self {
|
|
||||||
Slot {
|
|
||||||
typ,
|
|
||||||
occupant: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn with_occupant(typ: SlotClass, occupant: SlotOccupant) -> Self {
|
|
||||||
Slot {
|
|
||||||
typ,
|
|
||||||
occupant: Some(occupant),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_fields(&self) -> BTreeMap<LogicSlotType, LogicField> {
|
|
||||||
let mut copy = self
|
|
||||||
.occupant
|
|
||||||
.as_ref()
|
|
||||||
.map(|occupant| occupant.get_fields())
|
|
||||||
.unwrap_or_default();
|
|
||||||
copy.insert(
|
|
||||||
LogicSlotType::Occupied,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: if self.occupant.is_some() { 1.0 } else { 0.0 },
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy.insert(
|
|
||||||
LogicSlotType::OccupantHash,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: self
|
|
||||||
.occupant
|
|
||||||
.as_ref()
|
|
||||||
.map(|occupant| occupant.prefab_hash as f64)
|
|
||||||
.unwrap_or(0.0),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy.insert(
|
|
||||||
LogicSlotType::Quantity,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: self
|
|
||||||
.occupant
|
|
||||||
.as_ref()
|
|
||||||
.map(|occupant| occupant.quantity as f64)
|
|
||||||
.unwrap_or(0.0),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy.insert(
|
|
||||||
LogicSlotType::Damage,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: self
|
|
||||||
.occupant
|
|
||||||
.as_ref()
|
|
||||||
.map(|occupant| occupant.damage)
|
|
||||||
.unwrap_or(0.0),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy.insert(
|
|
||||||
LogicSlotType::Class,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: self.typ as u32 as f64,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy.insert(
|
|
||||||
LogicSlotType::MaxQuantity,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: self
|
|
||||||
.occupant
|
|
||||||
.as_ref()
|
|
||||||
.map(|occupant| occupant.max_quantity as f64)
|
|
||||||
.unwrap_or(0.0),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy.insert(
|
|
||||||
LogicSlotType::PrefabHash,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: self
|
|
||||||
.occupant
|
|
||||||
.as_ref()
|
|
||||||
.map(|occupant| occupant.prefab_hash as f64)
|
|
||||||
.unwrap_or(0.0),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy.insert(
|
|
||||||
LogicSlotType::SortingClass,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: self
|
|
||||||
.occupant
|
|
||||||
.as_ref()
|
|
||||||
.map(|occupant| occupant.sorting_class as u32 as f64)
|
|
||||||
.unwrap_or(0.0),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy.insert(
|
|
||||||
LogicSlotType::ReferenceId,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: self
|
|
||||||
.occupant
|
|
||||||
.as_ref()
|
|
||||||
.map(|occupant| occupant.id as f64)
|
|
||||||
.unwrap_or(0.0),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_field(&self, field: LogicSlotType) -> f64 {
|
|
||||||
let fields = self.get_fields();
|
|
||||||
fields
|
|
||||||
.get(&field)
|
|
||||||
.map(|field| match field.field_type {
|
|
||||||
MemoryAccess::Read | MemoryAccess::ReadWrite => field.value,
|
|
||||||
_ => 0.0,
|
|
||||||
})
|
|
||||||
.unwrap_or(0.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn can_logic_read(&self, field: LogicSlotType) -> bool {
|
|
||||||
match field {
|
|
||||||
LogicSlotType::Pressure | LogicSlotType::Temperature | LogicSlotType::Volume => {
|
|
||||||
matches!(
|
|
||||||
self.typ,
|
|
||||||
SlotClass::GasCanister | SlotClass::LiquidCanister | SlotClass::LiquidBottle
|
|
||||||
)
|
|
||||||
}
|
|
||||||
LogicSlotType::Charge | LogicSlotType::ChargeRatio => {
|
|
||||||
matches!(self.typ, SlotClass::Battery)
|
|
||||||
}
|
|
||||||
LogicSlotType::Open => matches!(
|
|
||||||
self.typ,
|
|
||||||
SlotClass::Helmet | SlotClass::Tool | SlotClass::Appliance
|
|
||||||
),
|
|
||||||
LogicSlotType::Lock => matches!(self.typ, SlotClass::Helmet),
|
|
||||||
LogicSlotType::FilterType => matches!(self.typ, SlotClass::GasFilter),
|
|
||||||
_ => {
|
|
||||||
if let Some(occupant) = self.occupant.as_ref() {
|
|
||||||
occupant.can_logic_read(field)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn can_logic_write(&self, field: LogicSlotType) -> bool {
|
|
||||||
match field {
|
|
||||||
LogicSlotType::Open => matches!(
|
|
||||||
self.typ,
|
|
||||||
SlotClass::Helmet
|
|
||||||
| SlotClass::GasCanister
|
|
||||||
| SlotClass::LiquidCanister
|
|
||||||
| SlotClass::LiquidBottle
|
|
||||||
),
|
|
||||||
LogicSlotType::On => matches!(
|
|
||||||
self.typ,
|
|
||||||
SlotClass::Helmet | SlotClass::Tool | SlotClass::Appliance
|
|
||||||
),
|
|
||||||
LogicSlotType::Lock => matches!(self.typ, SlotClass::Helmet),
|
|
||||||
_ => {
|
|
||||||
if let Some(occupant) = self.occupant.as_ref() {
|
|
||||||
occupant.can_logic_write(field)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_field(&mut self, typ: LogicSlotType, val: f64, force: bool) -> Result<(), ICError> {
|
|
||||||
if matches!(
|
|
||||||
typ,
|
|
||||||
LogicSlotType::Occupied
|
|
||||||
| LogicSlotType::OccupantHash
|
|
||||||
| LogicSlotType::Class
|
|
||||||
| LogicSlotType::PrefabHash
|
|
||||||
| LogicSlotType::SortingClass
|
|
||||||
| LogicSlotType::ReferenceId
|
|
||||||
) {
|
|
||||||
return Err(ICError::ReadOnlyField(typ.to_string()));
|
|
||||||
}
|
|
||||||
if let Some(occupant) = self.occupant.as_mut() {
|
|
||||||
occupant.set_field(typ, val, force)
|
|
||||||
} else {
|
|
||||||
Err(ICError::SlotNotOccupied)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct Prefab {
|
|
||||||
pub name: String,
|
|
||||||
pub hash: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Prefab {
|
|
||||||
pub fn new(name: &str) -> Self {
|
|
||||||
Prefab {
|
|
||||||
name: name.to_owned(),
|
|
||||||
hash: const_crc32::crc32(name.as_bytes()) as i32,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct Device {
|
|
||||||
pub id: u32,
|
|
||||||
pub name: Option<String>,
|
|
||||||
pub name_hash: Option<i32>,
|
|
||||||
pub prefab: Option<Prefab>,
|
|
||||||
pub slots: Vec<Slot>,
|
|
||||||
pub reagents: BTreeMap<ReagentMode, BTreeMap<i32, f64>>,
|
|
||||||
pub ic: Option<u32>,
|
|
||||||
pub connections: Vec<Connection>,
|
|
||||||
fields: BTreeMap<LogicType, LogicField>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device {
|
|
||||||
pub fn new(id: u32) -> Self {
|
|
||||||
Device {
|
|
||||||
id,
|
|
||||||
name: None,
|
|
||||||
name_hash: None,
|
|
||||||
prefab: None,
|
|
||||||
fields: BTreeMap::new(),
|
|
||||||
slots: Vec::new(),
|
|
||||||
reagents: BTreeMap::new(),
|
|
||||||
ic: None,
|
|
||||||
connections: vec![Connection::CableNetwork {
|
|
||||||
net: None,
|
|
||||||
typ: CableConnectionType::default(),
|
|
||||||
}],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_ic(id: u32, ic: u32) -> Self {
|
|
||||||
let mut device = Device::new(id);
|
|
||||||
device.ic = Some(ic);
|
|
||||||
device.connections = vec![
|
|
||||||
Connection::CableNetwork {
|
|
||||||
net: None,
|
|
||||||
typ: CableConnectionType::Data,
|
|
||||||
},
|
|
||||||
Connection::CableNetwork {
|
|
||||||
net: None,
|
|
||||||
typ: CableConnectionType::Power,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
device.prefab = Some(Prefab::new("StructureCircuitHousing"));
|
|
||||||
device.fields.extend(vec![
|
|
||||||
(
|
|
||||||
LogicType::Setting,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::ReadWrite,
|
|
||||||
value: 0.0,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
LogicType::RequiredPower,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: 0.0,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
LogicType::PrefabHash,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: -128473777.0,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
let occupant = SlotOccupant::new(ic, -744098481);
|
|
||||||
device.slots.push(Slot::with_occupant(
|
|
||||||
SlotClass::ProgrammableChip,
|
|
||||||
// -744098481 = ItemIntegratedCircuit10
|
|
||||||
occupant,
|
|
||||||
));
|
|
||||||
|
|
||||||
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
|
|
||||||
.circuit_holders
|
|
||||||
.get(ic_id)
|
|
||||||
.expect("our own ic to exist")
|
|
||||||
.borrow();
|
|
||||||
copy.insert(
|
|
||||||
LogicType::LineNumber,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::ReadWrite,
|
|
||||||
value: ic.ip() as f64,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy.insert(
|
|
||||||
LogicType::Error,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: match *ic.state.borrow() {
|
|
||||||
ICState::Error(_) => 1.0,
|
|
||||||
_ => 0.0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if self.has_power_state() {
|
|
||||||
copy.insert(
|
|
||||||
LogicType::Power,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: if self.has_power_connection() {
|
|
||||||
1.0
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
copy.insert(
|
|
||||||
LogicType::ReferenceId,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::Read,
|
|
||||||
value: self.id as f64,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
copy
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_network_id(&self, connection: usize) -> Result<u32, ICError> {
|
|
||||||
if connection >= self.connections.len() {
|
|
||||||
Err(ICError::ConnectionIndexOutOfRange(
|
|
||||||
connection,
|
|
||||||
self.connections.len(),
|
|
||||||
))
|
|
||||||
} else if let Connection::CableNetwork {
|
|
||||||
net: network_id, ..
|
|
||||||
} = self.connections[connection]
|
|
||||||
{
|
|
||||||
if let Some(network_id) = network_id {
|
|
||||||
Ok(network_id)
|
|
||||||
} else {
|
|
||||||
Err(ICError::NetworkNotConnected(connection))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(ICError::NotACableConnection(connection))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn can_logic_read(&self, field: LogicType) -> bool {
|
|
||||||
match field {
|
|
||||||
LogicType::ReferenceId => true,
|
|
||||||
LogicType::LineNumber | LogicType::Error if self.ic.is_some() => true,
|
|
||||||
LogicType::Power if self.has_power_state() => true,
|
|
||||||
_ => {
|
|
||||||
if let Some(logic) = self.fields.get(&field) {
|
|
||||||
matches!(
|
|
||||||
logic.field_type,
|
|
||||||
MemoryAccess::Read | MemoryAccess::ReadWrite
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn can_logic_write(&self, field: LogicType) -> bool {
|
|
||||||
match field {
|
|
||||||
LogicType::ReferenceId => false,
|
|
||||||
LogicType::LineNumber if self.ic.is_some() => true,
|
|
||||||
_ => {
|
|
||||||
if let Some(logic) = self.fields.get(&field) {
|
|
||||||
matches!(
|
|
||||||
logic.field_type,
|
|
||||||
MemoryAccess::Write | MemoryAccess::ReadWrite
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn can_slot_logic_read(&self, field: LogicSlotType, slot: usize) -> bool {
|
|
||||||
if self.slots.is_empty() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let Some(slot) = self.slots.get(slot) else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
slot.can_logic_read(field)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn can_slot_logic_write(&self, field: LogicSlotType, slot: usize) -> bool {
|
|
||||||
if self.slots.is_empty() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let Some(slot) = self.slots.get(slot) else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
slot.can_logic_write(field)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_field(&self, typ: LogicType, vm: &VM) -> Result<f64, ICError> {
|
|
||||||
if typ == LogicType::LineNumber && self.ic.is_some() {
|
|
||||||
let ic = vm
|
|
||||||
.circuit_holders
|
|
||||||
.get(&self.ic.unwrap())
|
|
||||||
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
|
|
||||||
.borrow();
|
|
||||||
Ok(ic.ip() as f64)
|
|
||||||
} else if let Some(field) = self.get_fields(vm).get(&typ) {
|
|
||||||
if field.field_type == MemoryAccess::Read || field.field_type == MemoryAccess::ReadWrite
|
|
||||||
{
|
|
||||||
Ok(field.value)
|
|
||||||
} else {
|
|
||||||
Err(ICError::WriteOnlyField(typ.to_string()))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(ICError::DeviceHasNoField(typ.to_string()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_field(
|
|
||||||
&mut self,
|
|
||||||
typ: LogicType,
|
|
||||||
val: f64,
|
|
||||||
vm: &VM,
|
|
||||||
force: bool,
|
|
||||||
) -> Result<(), ICError> {
|
|
||||||
if typ == LogicType::ReferenceId
|
|
||||||
|| (typ == LogicType::Error && self.ic.is_some())
|
|
||||||
|| (typ == LogicType::Power && self.has_power_state())
|
|
||||||
{
|
|
||||||
Err(ICError::ReadOnlyField(typ.to_string()))
|
|
||||||
} else if typ == LogicType::LineNumber && self.ic.is_some() {
|
|
||||||
let ic = vm
|
|
||||||
.circuit_holders
|
|
||||||
.get(&self.ic.unwrap())
|
|
||||||
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
|
|
||||||
.borrow();
|
|
||||||
ic.set_ip(val as u32);
|
|
||||||
Ok(())
|
|
||||||
} else if let Some(field) = self.fields.get_mut(&typ) {
|
|
||||||
if field.field_type == MemoryAccess::Write
|
|
||||||
|| field.field_type == MemoryAccess::ReadWrite
|
|
||||||
|| force
|
|
||||||
{
|
|
||||||
field.value = val;
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(ICError::ReadOnlyField(typ.to_string()))
|
|
||||||
}
|
|
||||||
} else if force {
|
|
||||||
self.fields.insert(
|
|
||||||
typ,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::ReadWrite,
|
|
||||||
value: val,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(ICError::DeviceHasNoField(typ.to_string()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_slot_field(&self, index: f64, typ: LogicSlotType, vm: &VM) -> Result<f64, ICError> {
|
|
||||||
let slot = self
|
|
||||||
.slots
|
|
||||||
.get(index as usize)
|
|
||||||
.ok_or(ICError::SlotIndexOutOfRange(index))?;
|
|
||||||
if slot.typ == SlotClass::ProgrammableChip
|
|
||||||
&& slot.occupant.is_some()
|
|
||||||
&& self.ic.is_some()
|
|
||||||
&& typ == LogicSlotType::LineNumber
|
|
||||||
{
|
|
||||||
let ic = vm
|
|
||||||
.circuit_holders
|
|
||||||
.get(&self.ic.unwrap())
|
|
||||||
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
|
|
||||||
.borrow();
|
|
||||||
Ok(ic.ip() as f64)
|
|
||||||
} else {
|
|
||||||
Ok(slot.get_field(typ))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_slot_fields(
|
|
||||||
&self,
|
|
||||||
index: f64,
|
|
||||||
vm: &VM,
|
|
||||||
) -> Result<BTreeMap<LogicSlotType, LogicField>, ICError> {
|
|
||||||
let slot = self
|
|
||||||
.slots
|
|
||||||
.get(index as usize)
|
|
||||||
.ok_or(ICError::SlotIndexOutOfRange(index))?;
|
|
||||||
let mut fields = slot.get_fields();
|
|
||||||
if slot.typ == SlotClass::ProgrammableChip && slot.occupant.is_some() && self.ic.is_some() {
|
|
||||||
let ic = vm
|
|
||||||
.circuit_holders
|
|
||||||
.get(&self.ic.unwrap())
|
|
||||||
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
|
|
||||||
.borrow();
|
|
||||||
fields.insert(
|
|
||||||
LogicSlotType::LineNumber,
|
|
||||||
LogicField {
|
|
||||||
field_type: MemoryAccess::ReadWrite,
|
|
||||||
value: ic.ip() as f64,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Ok(fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_slot_field(
|
|
||||||
&mut self,
|
|
||||||
index: f64,
|
|
||||||
typ: LogicSlotType,
|
|
||||||
val: f64,
|
|
||||||
_vm: &VM,
|
|
||||||
force: bool,
|
|
||||||
) -> Result<(), ICError> {
|
|
||||||
let slot = self
|
|
||||||
.slots
|
|
||||||
.get_mut(index as usize)
|
|
||||||
.ok_or(ICError::SlotIndexOutOfRange(index))?;
|
|
||||||
slot.set_field(typ, val, force)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_slot(&self, index: f64) -> Result<&Slot, ICError> {
|
|
||||||
self.slots
|
|
||||||
.get(index as usize)
|
|
||||||
.ok_or(ICError::SlotIndexOutOfRange(index))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_reagent(&self, rm: &ReagentMode, reagent: f64) -> f64 {
|
|
||||||
if let Some(mode) = self.reagents.get(rm) {
|
|
||||||
if let Some(val) = mode.get(&(reagent as i32)) {
|
|
||||||
return *val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0.0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_name(&mut self, name: &str) {
|
|
||||||
self.name_hash = Some(const_crc32::crc32(name.as_bytes()) as i32);
|
|
||||||
self.name = Some(name.to_owned());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_power_state(&self) -> bool {
|
|
||||||
self.connections.iter().any(|conn| {
|
|
||||||
matches!(
|
|
||||||
conn,
|
|
||||||
Connection::CableNetwork {
|
|
||||||
typ: CableConnectionType::Power | CableConnectionType::PowerAndData,
|
|
||||||
..
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_power_connection(&self) -> bool {
|
|
||||||
self.connections.iter().any(|conn| {
|
|
||||||
matches!(
|
|
||||||
conn,
|
|
||||||
Connection::CableNetwork {
|
|
||||||
net: Some(_),
|
|
||||||
typ: CableConnectionType::Power | CableConnectionType::PowerAndData,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct DeviceTemplate {
|
|
||||||
pub id: Option<u32>,
|
|
||||||
pub name: Option<String>,
|
|
||||||
pub prefab_name: Option<String>,
|
|
||||||
pub slots: Vec<SlotTemplate>,
|
|
||||||
// pub reagents: BTreeMap<ReagentMode, BTreeMap<i32, f64>>,
|
|
||||||
pub connections: Vec<Connection>,
|
|
||||||
pub fields: BTreeMap<LogicType, LogicField>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device {
|
|
||||||
/// create a devive from a template and return the device, does not create it's own IC
|
|
||||||
pub fn from_template<F>(template: DeviceTemplate, mut id_fn: F) -> Self
|
|
||||||
where
|
|
||||||
F: FnMut() -> u32,
|
|
||||||
{
|
|
||||||
// id_fn *must* be captured not moved
|
|
||||||
#[allow(clippy::redundant_closure)]
|
|
||||||
let device_id = template.id.unwrap_or_else(|| id_fn());
|
|
||||||
let name_hash = template
|
|
||||||
.name
|
|
||||||
.as_ref()
|
|
||||||
.map(|name| const_crc32::crc32(name.as_bytes()) as i32);
|
|
||||||
|
|
||||||
#[allow(clippy::redundant_closure)]
|
|
||||||
let slots = template
|
|
||||||
.slots
|
|
||||||
.into_iter()
|
|
||||||
.map(|slot| Slot {
|
|
||||||
typ: slot.typ,
|
|
||||||
occupant: slot
|
|
||||||
.occupant
|
|
||||||
.map(|occupant| SlotOccupant::from_template(occupant, || id_fn())),
|
|
||||||
})
|
|
||||||
.collect_vec();
|
|
||||||
|
|
||||||
let ic = slots
|
|
||||||
.iter()
|
|
||||||
.find_map(|slot| {
|
|
||||||
if slot.typ == SlotClass::ProgrammableChip && slot.occupant.is_some() {
|
|
||||||
Some(slot.occupant.clone()).flatten()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(|occupant| occupant.id);
|
|
||||||
|
|
||||||
let fields = template.fields;
|
|
||||||
|
|
||||||
Device {
|
|
||||||
id: device_id,
|
|
||||||
name: template.name,
|
|
||||||
name_hash,
|
|
||||||
prefab: template.prefab_name.map(|name| Prefab::new(&name)),
|
|
||||||
slots,
|
|
||||||
// reagents: template.reagents,
|
|
||||||
reagents: BTreeMap::new(),
|
|
||||||
ic,
|
|
||||||
connections: template.connections,
|
|
||||||
fields,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> From<T> for DeviceTemplate
|
|
||||||
where
|
|
||||||
T: Deref<Target = Device>,
|
|
||||||
{
|
|
||||||
fn from(device: T) -> Self {
|
|
||||||
DeviceTemplate {
|
|
||||||
id: Some(device.id),
|
|
||||||
name: device.name.clone(),
|
|
||||||
prefab_name: device.prefab.as_ref().map(|prefab| prefab.name.clone()),
|
|
||||||
slots: device
|
|
||||||
.slots
|
|
||||||
.iter()
|
|
||||||
.map(|slot| SlotTemplate {
|
|
||||||
typ: slot.typ,
|
|
||||||
occupant: slot.occupant.as_ref().map(|occupant| SlotOccupantTemplate {
|
|
||||||
id: Some(occupant.id),
|
|
||||||
fields: occupant.get_fields(),
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.collect_vec(),
|
|
||||||
connections: device.connections.clone(),
|
|
||||||
fields: device.fields.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -208,10 +208,14 @@ pub enum ICError {
|
|||||||
BadGeneratedValueParse(String, String),
|
BadGeneratedValueParse(String, String),
|
||||||
#[error("IC with id {0} is not sloted into a circuit holder")]
|
#[error("IC with id {0} is not sloted into a circuit holder")]
|
||||||
NoCircuitHolder(ObjectID),
|
NoCircuitHolder(ObjectID),
|
||||||
|
#[error("IC with id {0} is sloted into a circuit holder with no logic interface?")]
|
||||||
|
CircuitHolderNotLogicable(ObjectID),
|
||||||
#[error("object {0} is not slot writeable")]
|
#[error("object {0} is not slot writeable")]
|
||||||
NotSlotWriteable(ObjectID),
|
NotSlotWriteable(ObjectID),
|
||||||
#[error("object {0} does not use reagents ")]
|
#[error("object {0} does not use reagents ")]
|
||||||
NotReagentReadable(ObjectID),
|
NotReagentReadable(ObjectID),
|
||||||
|
#[error("object {0} is not slot logicable")]
|
||||||
|
NotLogicable(ObjectID),
|
||||||
#[error("{0} is not a valid number of sleep seconds")]
|
#[error("{0} is not a valid number of sleep seconds")]
|
||||||
SleepDurationError(f64),
|
SleepDurationError(f64),
|
||||||
#[error("{0} can not be added to {1} ")]
|
#[error("{0} can not be added to {1} ")]
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ use crate::{
|
|||||||
operands::{InstOperand, RegisterSpec},
|
operands::{InstOperand, RegisterSpec},
|
||||||
traits::*,
|
traits::*,
|
||||||
},
|
},
|
||||||
object::{errors::MemoryError, traits::*, ObjectID},
|
object::{
|
||||||
|
errors::{LogicError, MemoryError},
|
||||||
|
traits::*,
|
||||||
|
ObjectID,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
pub trait IC10Marker: IntegratedCircuit {}
|
pub trait IC10Marker: IntegratedCircuit {}
|
||||||
@@ -862,6 +866,9 @@ impl<T: IC10Marker> BdseInstruction for T {
|
|||||||
if self
|
if self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.get_logicable_from_index(device, connection)
|
.get_logicable_from_index(device, connection)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
@@ -879,6 +886,9 @@ impl<T: IC10Marker> BdsealInstruction for T {
|
|||||||
if self
|
if self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.get_logicable_from_index(device, connection)
|
.get_logicable_from_index(device, connection)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
@@ -897,6 +907,9 @@ impl<T: IC10Marker> BrdseInstruction for T {
|
|||||||
if self
|
if self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.get_logicable_from_index(device, connection)
|
.get_logicable_from_index(device, connection)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
@@ -914,6 +927,9 @@ impl<T: IC10Marker> BdnsInstruction for T {
|
|||||||
if self
|
if self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.get_logicable_from_index(device, connection)
|
.get_logicable_from_index(device, connection)
|
||||||
.is_none()
|
.is_none()
|
||||||
{
|
{
|
||||||
@@ -931,6 +947,9 @@ impl<T: IC10Marker> BdnsalInstruction for T {
|
|||||||
if self
|
if self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.get_logicable_from_index(device, connection)
|
.get_logicable_from_index(device, connection)
|
||||||
.is_none()
|
.is_none()
|
||||||
{
|
{
|
||||||
@@ -949,6 +968,9 @@ impl<T: IC10Marker> BrdnsInstruction for T {
|
|||||||
if self
|
if self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.get_logicable_from_index(device, connection)
|
.get_logicable_from_index(device, connection)
|
||||||
.is_none()
|
.is_none()
|
||||||
{
|
{
|
||||||
@@ -1319,15 +1341,14 @@ impl<T: IC10Marker> SdseInstruction for T {
|
|||||||
target,
|
target,
|
||||||
} = r.as_register(self)?;
|
} = r.as_register(self)?;
|
||||||
let (device, connection) = d.as_device(self)?;
|
let (device, connection) = d.as_device(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.get_logicable_from_index(device, connection);
|
.get_logicable_from_index(device, connection);
|
||||||
self.set_register(
|
self.set_register(indirection, target, if obj.is_some() { 1.0 } else { 0.0 })?;
|
||||||
indirection,
|
|
||||||
target,
|
|
||||||
if logicable.is_some() { 1.0 } else { 0.0 },
|
|
||||||
)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1339,15 +1360,14 @@ impl<T: IC10Marker> SdnsInstruction for T {
|
|||||||
target,
|
target,
|
||||||
} = r.as_register(self)?;
|
} = r.as_register(self)?;
|
||||||
let (device, connection) = d.as_device(self)?;
|
let (device, connection) = d.as_device(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.get_logicable_from_index(device, connection);
|
.get_logicable_from_index(device, connection);
|
||||||
self.set_register(
|
self.set_register(indirection, target, if obj.is_none() { 1.0 } else { 0.0 })?;
|
||||||
indirection,
|
|
||||||
target,
|
|
||||||
if logicable.is_none() { 1.0 } else { 0.0 },
|
|
||||||
)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1968,12 +1988,16 @@ impl<T: IC10Marker> GetInstruction for T {
|
|||||||
} = r.as_register(self)?;
|
} = r.as_register(self)?;
|
||||||
let address = address.as_value(self)?;
|
let address = address.as_value(self)?;
|
||||||
let (device, connection) = d.as_device(self)?;
|
let (device, connection) = d.as_device(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.get_logicable_from_index(device, connection)
|
.get_logicable_from_index(device, connection)
|
||||||
.ok_or(ICError::DeviceNotSet)?;
|
.ok_or(ICError::DeviceNotSet)?;
|
||||||
let memory = logicable
|
let obj_ref = obj.borrow();
|
||||||
|
let memory = obj_ref
|
||||||
.as_memory_readable()
|
.as_memory_readable()
|
||||||
.ok_or(MemoryError::NotReadable)?;
|
.ok_or(MemoryError::NotReadable)?;
|
||||||
self.set_register(indirection, target, memory.get_memory(address as i32)?)?;
|
self.set_register(indirection, target, memory.get_memory(address as i32)?)?;
|
||||||
@@ -1995,12 +2019,16 @@ impl<T: IC10Marker> GetdInstruction for T {
|
|||||||
} = r.as_register(self)?;
|
} = r.as_register(self)?;
|
||||||
let id = id.as_value(self)?;
|
let id = id.as_value(self)?;
|
||||||
let address = address.as_value(self)?;
|
let address = address.as_value(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.get_logicable_from_id(id as ObjectID, None)
|
.get_logicable_from_id(id as ObjectID, None)
|
||||||
.ok_or(ICError::DeviceNotSet)?;
|
.ok_or(ICError::DeviceNotSet)?;
|
||||||
let memory = logicable
|
let obj_ref = obj.borrow();
|
||||||
|
let memory = obj_ref
|
||||||
.as_memory_readable()
|
.as_memory_readable()
|
||||||
.ok_or(MemoryError::NotReadable)?;
|
.ok_or(MemoryError::NotReadable)?;
|
||||||
self.set_register(indirection, target, memory.get_memory(address as i32)?)?;
|
self.set_register(indirection, target, memory.get_memory(address as i32)?)?;
|
||||||
@@ -2019,13 +2047,17 @@ impl<T: IC10Marker> PutInstruction for T {
|
|||||||
let (device, connection) = d.as_device(self)?;
|
let (device, connection) = d.as_device(self)?;
|
||||||
let address = address.as_value(self)?;
|
let address = address.as_value(self)?;
|
||||||
let value = value.as_value(self)?;
|
let value = value.as_value(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
.get_logicable_from_index_mut(device, connection)
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
|
.get_logicable_from_index(device, connection)
|
||||||
.ok_or(ICError::DeviceNotSet)?;
|
.ok_or(ICError::DeviceNotSet)?;
|
||||||
let memory = logicable
|
let mut obj_ref = obj.borrow_mut();
|
||||||
.as_memory_writable()
|
let memory = obj_ref
|
||||||
|
.as_mut_memory_writable()
|
||||||
.ok_or(MemoryError::NotWriteable)?;
|
.ok_or(MemoryError::NotWriteable)?;
|
||||||
memory.set_memory(address as i32, value)?;
|
memory.set_memory(address as i32, value)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -2043,13 +2075,17 @@ impl<T: IC10Marker> PutdInstruction for T {
|
|||||||
let id = id.as_value(self)?;
|
let id = id.as_value(self)?;
|
||||||
let address = address.as_value(self)?;
|
let address = address.as_value(self)?;
|
||||||
let value = value.as_value(self)?;
|
let value = value.as_value(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
.get_logicable_from_id_mut(id as ObjectID, None)
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
|
.get_logicable_from_id(id as ObjectID, None)
|
||||||
.ok_or(ICError::DeviceNotSet)?;
|
.ok_or(ICError::DeviceNotSet)?;
|
||||||
let memory = logicable
|
let mut obj_ref = obj.borrow_mut();
|
||||||
.as_memory_writable()
|
let memory = obj_ref
|
||||||
|
.as_mut_memory_writable()
|
||||||
.ok_or(MemoryError::NotWriteable)?;
|
.ok_or(MemoryError::NotWriteable)?;
|
||||||
memory.set_memory(address as i32, value)?;
|
memory.set_memory(address as i32, value)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -2060,13 +2096,17 @@ impl<T: IC10Marker> ClrInstruction for T {
|
|||||||
/// clr d?
|
/// clr d?
|
||||||
fn execute_inner(&mut self, d: &InstOperand) -> Result<(), ICError> {
|
fn execute_inner(&mut self, d: &InstOperand) -> Result<(), ICError> {
|
||||||
let (device, connection) = d.as_device(self)?;
|
let (device, connection) = d.as_device(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
.get_logicable_from_index_mut(device, connection)
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
|
.get_logicable_from_index(device, connection)
|
||||||
.ok_or(ICError::DeviceNotSet)?;
|
.ok_or(ICError::DeviceNotSet)?;
|
||||||
let memory = logicable
|
let mut obj_ref = obj.borrow_mut();
|
||||||
.as_memory_writable()
|
let memory = obj_ref
|
||||||
|
.as_mut_memory_writable()
|
||||||
.ok_or(MemoryError::NotWriteable)?;
|
.ok_or(MemoryError::NotWriteable)?;
|
||||||
memory.clear_memory()?;
|
memory.clear_memory()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -2076,13 +2116,17 @@ impl<T: IC10Marker> ClrdInstruction for T {
|
|||||||
/// clrd id(r?|num)
|
/// clrd id(r?|num)
|
||||||
fn execute_inner(&mut self, id: &InstOperand) -> Result<(), ICError> {
|
fn execute_inner(&mut self, id: &InstOperand) -> Result<(), ICError> {
|
||||||
let id = id.as_value(self)?;
|
let id = id.as_value(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
.get_logicable_from_id_mut(id as ObjectID, None)
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
|
.get_logicable_from_id(id as ObjectID, None)
|
||||||
.ok_or(ICError::DeviceNotSet)?;
|
.ok_or(ICError::DeviceNotSet)?;
|
||||||
let memory = logicable
|
let mut obj_ref = obj.borrow_mut();
|
||||||
.as_memory_writable()
|
let memory = obj_ref
|
||||||
|
.as_mut_memory_writable()
|
||||||
.ok_or(MemoryError::NotWriteable)?;
|
.ok_or(MemoryError::NotWriteable)?;
|
||||||
memory.clear_memory()?;
|
memory.clear_memory()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -2100,11 +2144,22 @@ impl<T: IC10Marker> SInstruction for T {
|
|||||||
let (device, connection) = d.as_device(self)?;
|
let (device, connection) = d.as_device(self)?;
|
||||||
let logic_type = logic_type.as_logic_type(self)?;
|
let logic_type = logic_type.as_logic_type(self)?;
|
||||||
let val = r.as_value(self)?;
|
let val = r.as_value(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
.get_logicable_from_index_mut(device, connection)
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
|
.get_logicable_from_index(device, connection)
|
||||||
.ok_or(ICError::DeviceNotSet)?;
|
.ok_or(ICError::DeviceNotSet)?;
|
||||||
|
let mut obj_ref = obj.borrow_mut();
|
||||||
|
let device_id = obj_ref.get_id();
|
||||||
|
let logicable = obj_ref
|
||||||
|
.as_mut_logicable()
|
||||||
|
.ok_or(ICError::NotLogicable(device_id))?;
|
||||||
|
if !logicable.can_logic_write(logic_type) {
|
||||||
|
return Err(LogicError::CantWrite(logic_type).into());
|
||||||
|
}
|
||||||
logicable.set_logic(logic_type, val, false)?;
|
logicable.set_logic(logic_type, val, false)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -2121,11 +2176,22 @@ impl<T: IC10Marker> SdInstruction for T {
|
|||||||
let id = id.as_value(self)?;
|
let id = id.as_value(self)?;
|
||||||
let logic_type = logic_type.as_logic_type(self)?;
|
let logic_type = logic_type.as_logic_type(self)?;
|
||||||
let val = r.as_value(self)?;
|
let val = r.as_value(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
.get_logicable_from_id_mut(id as ObjectID, None)
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
|
.get_logicable_from_id(id as ObjectID, None)
|
||||||
.ok_or(ICError::DeviceNotSet)?;
|
.ok_or(ICError::DeviceNotSet)?;
|
||||||
|
let mut obj_ref = obj.borrow_mut();
|
||||||
|
let device_id = obj_ref.get_id();
|
||||||
|
let logicable = obj_ref
|
||||||
|
.as_mut_logicable()
|
||||||
|
.ok_or(ICError::NotLogicable(device_id))?;
|
||||||
|
if !logicable.can_logic_write(logic_type) {
|
||||||
|
return Err(LogicError::CantWrite(logic_type).into());
|
||||||
|
}
|
||||||
logicable.set_logic(logic_type, val, false)?;
|
logicable.set_logic(logic_type, val, false)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -2144,14 +2210,26 @@ impl<T: IC10Marker> SsInstruction for T {
|
|||||||
let slot_index = slot_index.as_value(self)?;
|
let slot_index = slot_index.as_value(self)?;
|
||||||
let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?;
|
let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?;
|
||||||
let val = r.as_value(self)?;
|
let val = r.as_value(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
.get_logicable_from_index_mut(device, connection)
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
|
.get_logicable_from_index(device, connection)
|
||||||
.ok_or(ICError::DeviceNotSet)?;
|
.ok_or(ICError::DeviceNotSet)?;
|
||||||
|
let mut obj_ref = obj.borrow_mut();
|
||||||
|
let device_id = obj_ref.get_id();
|
||||||
|
let logicable = obj_ref
|
||||||
|
.as_mut_logicable()
|
||||||
|
.ok_or(ICError::NotLogicable(device_id))?;
|
||||||
|
let device_id = logicable.get_id();
|
||||||
let device = logicable
|
let device = logicable
|
||||||
.as_mut_device()
|
.as_mut_device()
|
||||||
.ok_or(ICError::NotSlotWriteable(logicable.get_id()))?;
|
.ok_or(ICError::NotSlotWriteable(device_id))?;
|
||||||
|
if !device.can_slot_logic_write(logic_slot_type, slot_index) {
|
||||||
|
return Err(LogicError::CantSlotWrite(logic_slot_type, slot_index).into());
|
||||||
|
}
|
||||||
device.set_slot_logic(logic_slot_type, slot_index, val, false)?;
|
device.set_slot_logic(logic_slot_type, slot_index, val, false)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -2242,11 +2320,21 @@ impl<T: IC10Marker> LInstruction for T {
|
|||||||
} = r.as_register(self)?;
|
} = r.as_register(self)?;
|
||||||
let (device, connection) = d.as_device(self)?;
|
let (device, connection) = d.as_device(self)?;
|
||||||
let logic_type = logic_type.as_logic_type(self)?;
|
let logic_type = logic_type.as_logic_type(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.get_logicable_from_index(device, connection)
|
.get_logicable_from_index(device, connection)
|
||||||
.ok_or(ICError::DeviceNotSet)?;
|
.ok_or(ICError::DeviceNotSet)?;
|
||||||
|
let obj_ref = obj.borrow();
|
||||||
|
let logicable = obj_ref
|
||||||
|
.as_logicable()
|
||||||
|
.ok_or(ICError::NotLogicable(obj_ref.get_id()))?;
|
||||||
|
if !logicable.can_logic_read(logic_type) {
|
||||||
|
return Err(LogicError::CantRead(logic_type).into());
|
||||||
|
}
|
||||||
self.set_register(indirection, target, logicable.get_logic(logic_type)?)?;
|
self.set_register(indirection, target, logicable.get_logic(logic_type)?)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -2266,11 +2354,21 @@ impl<T: IC10Marker> LdInstruction for T {
|
|||||||
} = r.as_register(self)?;
|
} = r.as_register(self)?;
|
||||||
let id = id.as_value(self)?;
|
let id = id.as_value(self)?;
|
||||||
let logic_type = logic_type.as_logic_type(self)?;
|
let logic_type = logic_type.as_logic_type(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.get_logicable_from_id(id as ObjectID, None)
|
.get_logicable_from_id(id as ObjectID, None)
|
||||||
.ok_or(ICError::DeviceNotSet)?;
|
.ok_or(ICError::DeviceNotSet)?;
|
||||||
|
let obj_ref = obj.borrow();
|
||||||
|
let logicable = obj_ref
|
||||||
|
.as_logicable()
|
||||||
|
.ok_or(ICError::NotLogicable(obj_ref.get_id()))?;
|
||||||
|
if !logicable.can_logic_read(logic_type) {
|
||||||
|
return Err(LogicError::CantRead(logic_type).into());
|
||||||
|
}
|
||||||
self.set_register(indirection, target, logicable.get_logic(logic_type)?)?;
|
self.set_register(indirection, target, logicable.get_logic(logic_type)?)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -2292,11 +2390,21 @@ impl<T: IC10Marker> LsInstruction for T {
|
|||||||
let (device, connection) = d.as_device(self)?;
|
let (device, connection) = d.as_device(self)?;
|
||||||
let slot_index = slot_index.as_value(self)?;
|
let slot_index = slot_index.as_value(self)?;
|
||||||
let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?;
|
let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.get_logicable_from_index(device, connection)
|
.get_logicable_from_index(device, connection)
|
||||||
.ok_or(ICError::DeviceNotSet)?;
|
.ok_or(ICError::DeviceNotSet)?;
|
||||||
|
let obj_ref = obj.borrow();
|
||||||
|
let logicable = obj_ref
|
||||||
|
.as_logicable()
|
||||||
|
.ok_or(ICError::NotLogicable(obj_ref.get_id()))?;
|
||||||
|
if !logicable.can_slot_logic_read(logic_slot_type, slot_index) {
|
||||||
|
return Err(LogicError::CantSlotRead(logic_slot_type, slot_index).into());
|
||||||
|
}
|
||||||
self.set_register(
|
self.set_register(
|
||||||
indirection,
|
indirection,
|
||||||
target,
|
target,
|
||||||
@@ -2322,11 +2430,18 @@ impl<T: IC10Marker> LrInstruction for T {
|
|||||||
let (device, connection) = d.as_device(self)?;
|
let (device, connection) = d.as_device(self)?;
|
||||||
let reagent_mode = reagent_mode.as_reagent_mode(self)?;
|
let reagent_mode = reagent_mode.as_reagent_mode(self)?;
|
||||||
let int = int.as_value(self)?;
|
let int = int.as_value(self)?;
|
||||||
let logicable = self
|
let obj = self
|
||||||
.get_circuit_holder()
|
.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow()
|
||||||
|
.as_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.get_logicable_from_index(device, connection)
|
.get_logicable_from_index(device, connection)
|
||||||
.ok_or(ICError::DeviceNotSet)?;
|
.ok_or(ICError::DeviceNotSet)?;
|
||||||
|
let obj_ref = obj.borrow();
|
||||||
|
let logicable = obj_ref
|
||||||
|
.as_logicable()
|
||||||
|
.ok_or(ICError::NotLogicable(obj_ref.get_id()))?;
|
||||||
|
|
||||||
let result = match reagent_mode {
|
let result = match reagent_mode {
|
||||||
LogicReagentMode::Contents => {
|
LogicReagentMode::Contents => {
|
||||||
@@ -2505,6 +2620,9 @@ impl<T: IC10Marker> HcfInstruction for T {
|
|||||||
fn execute_inner(&mut self) -> Result<(), ICError> {
|
fn execute_inner(&mut self) -> Result<(), ICError> {
|
||||||
self.get_circuit_holder()
|
self.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||||
|
.borrow_mut()
|
||||||
|
.as_mut_circuit_holder()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.get_id()))?
|
||||||
.hault_and_catch_fire();
|
.hault_and_catch_fire();
|
||||||
self.set_state(ICState::HasCaughtFire);
|
self.set_state(ICState::HasCaughtFire);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -2513,7 +2631,7 @@ impl<T: IC10Marker> HcfInstruction for T {
|
|||||||
|
|
||||||
impl<T: IC10Marker> LabelInstruction for T {
|
impl<T: IC10Marker> LabelInstruction for T {
|
||||||
/// label d? str
|
/// label d? str
|
||||||
fn execute_inner(&mut self, d: &InstOperand, str: &InstOperand) -> Result<(), ICError> {
|
fn execute_inner(&mut self, _d: &InstOperand, _str: &InstOperand) -> Result<(), ICError> {
|
||||||
// No op, handled by program compilation, should never be called?
|
// No op, handled by program compilation, should never be called?
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
pub mod device;
|
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod grammar;
|
pub mod grammar;
|
||||||
pub mod interpreter;
|
pub mod interpreter;
|
||||||
|
|||||||
@@ -229,17 +229,17 @@ impl Storage for CableNetwork {
|
|||||||
fn slots_count(&self) -> usize {
|
fn slots_count(&self) -> usize {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
fn get_slot(&self, index: usize) -> Option<&crate::vm::object::Slot> {
|
fn get_slot(&self, _index: usize) -> Option<&crate::vm::object::Slot> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
fn get_slot_mut(&mut self, index: usize) -> Option<&mut crate::vm::object::Slot> {
|
fn get_slot_mut(&mut self, _index: usize) -> Option<&mut crate::vm::object::Slot> {
|
||||||
None
|
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![]
|
&mut []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +287,7 @@ impl Logicable for CableNetwork {
|
|||||||
};
|
};
|
||||||
Ok(self.channels[index])
|
Ok(self.channels[index])
|
||||||
}
|
}
|
||||||
fn set_logic(&mut self, lt: LogicType, value: f64, force: bool) -> Result<(), LogicError> {
|
fn set_logic(&mut self, lt: LogicType, value: f64, _force: bool) -> Result<(), LogicError> {
|
||||||
use LogicType::*;
|
use LogicType::*;
|
||||||
let index: usize = match lt {
|
let index: usize = match lt {
|
||||||
Channel0 => 0,
|
Channel0 => 0,
|
||||||
@@ -305,8 +305,8 @@ impl Logicable for CableNetwork {
|
|||||||
}
|
}
|
||||||
fn can_slot_logic_read(
|
fn can_slot_logic_read(
|
||||||
&self,
|
&self,
|
||||||
slt: crate::vm::enums::script_enums::LogicSlotType,
|
_slt: crate::vm::enums::script_enums::LogicSlotType,
|
||||||
index: f64,
|
_index: f64,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@@ -314,7 +314,6 @@ impl Logicable for CableNetwork {
|
|||||||
&self,
|
&self,
|
||||||
slt: crate::vm::enums::script_enums::LogicSlotType,
|
slt: crate::vm::enums::script_enums::LogicSlotType,
|
||||||
index: f64,
|
index: f64,
|
||||||
vm: &crate::vm::VM,
|
|
||||||
) -> Result<f64, LogicError> {
|
) -> Result<f64, LogicError> {
|
||||||
Err(LogicError::CantSlotRead(slt, index))
|
Err(LogicError::CantSlotRead(slt, index))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ impl VM {
|
|||||||
let default_network_key = network_id_space.next();
|
let default_network_key = network_id_space.next();
|
||||||
let networks = BTreeMap::new();
|
let networks = BTreeMap::new();
|
||||||
|
|
||||||
let mut vm = Rc::new(VM {
|
let vm = Rc::new(VM {
|
||||||
objects: RefCell::new(BTreeMap::new()),
|
objects: RefCell::new(BTreeMap::new()),
|
||||||
circuit_holders: RefCell::new(Vec::new()),
|
circuit_holders: RefCell::new(Vec::new()),
|
||||||
program_holders: RefCell::new(Vec::new()),
|
program_holders: RefCell::new(Vec::new()),
|
||||||
@@ -120,17 +120,19 @@ impl VM {
|
|||||||
.networks
|
.networks
|
||||||
.borrow()
|
.borrow()
|
||||||
.get(&net_id)
|
.get(&net_id)
|
||||||
|
.cloned()
|
||||||
.expect(&format!(
|
.expect(&format!(
|
||||||
"desync between vm and transaction networks: {net_id}"
|
"desync between vm and transaction networks: {net_id}"
|
||||||
))
|
));
|
||||||
.borrow_mut()
|
let mut net_ref = net.borrow_mut();
|
||||||
|
let net_interface = net_ref
|
||||||
.as_mut_network()
|
.as_mut_network()
|
||||||
.expect(&format!("non network network: {net_id}"));
|
.expect(&format!("non network network: {net_id}"));
|
||||||
for id in trans_net.devices {
|
for id in trans_net.devices {
|
||||||
net.add_data(id);
|
net_interface.add_data(id);
|
||||||
}
|
}
|
||||||
for id in trans_net.power_only {
|
for id in trans_net.power_only {
|
||||||
net.add_power(id);
|
net_interface.add_power(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,11 +175,9 @@ impl VM {
|
|||||||
obj.borrow_mut().set_id(new_id);
|
obj.borrow_mut().set_id(new_id);
|
||||||
self.objects.borrow_mut().insert(new_id, obj);
|
self.objects.borrow_mut().insert(new_id, obj);
|
||||||
|
|
||||||
self.objects
|
for obj in self.objects.borrow().values() {
|
||||||
.borrow_mut()
|
let mut obj_ref = obj.borrow_mut();
|
||||||
.iter_mut()
|
if let Some(device) = obj_ref.as_mut_device() {
|
||||||
.filter_map(|(_obj_id, obj)| obj.borrow_mut().as_mut_device())
|
|
||||||
.for_each(|device| {
|
|
||||||
device.get_slots_mut().iter_mut().for_each(|slot| {
|
device.get_slots_mut().iter_mut().for_each(|slot| {
|
||||||
if slot.parent == old_id {
|
if slot.parent == old_id {
|
||||||
slot.parent = new_id;
|
slot.parent = new_id;
|
||||||
@@ -189,7 +189,8 @@ impl VM {
|
|||||||
slot.occupant = Some(new_id);
|
slot.occupant = Some(new_id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.circuit_holders.borrow_mut().iter_mut().for_each(|id| {
|
self.circuit_holders.borrow_mut().iter_mut().for_each(|id| {
|
||||||
if *id == old_id {
|
if *id == old_id {
|
||||||
@@ -202,15 +203,13 @@ impl VM {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.networks.borrow().iter().for_each(|(_net_id, net)| {
|
self.networks.borrow().iter().for_each(|(_net_id, net)| {
|
||||||
let net_ref = net
|
let mut net_ref = net.borrow_mut();
|
||||||
.borrow_mut()
|
let net_interface = net_ref.as_mut_network().expect("non-network network");
|
||||||
.as_mut_network()
|
if net_interface.remove_data(old_id) {
|
||||||
.expect("non-network network");
|
net_interface.add_data(new_id);
|
||||||
if net_ref.remove_data(old_id) {
|
|
||||||
net_ref.add_data(new_id);
|
|
||||||
}
|
}
|
||||||
if net_ref.remove_power(old_id) {
|
if net_interface.remove_power(old_id) {
|
||||||
net_ref.add_power(new_id);
|
net_interface.add_power(new_id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.id_space.borrow_mut().free_id(old_id);
|
self.id_space.borrow_mut().free_id(old_id);
|
||||||
@@ -219,12 +218,14 @@ impl VM {
|
|||||||
|
|
||||||
/// Set program code if it's valid
|
/// Set program code if it's valid
|
||||||
pub fn set_code(self: &Rc<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
|
let obj = self
|
||||||
.objects
|
.objects
|
||||||
.borrow()
|
.borrow()
|
||||||
.get(&id)
|
.get(&id)
|
||||||
.ok_or(VMError::UnknownId(id))?
|
.cloned()
|
||||||
.borrow_mut()
|
.ok_or(VMError::UnknownId(id))?;
|
||||||
|
let mut obj_ref = obj.borrow_mut();
|
||||||
|
let programmable = obj_ref
|
||||||
.as_mut_programmable()
|
.as_mut_programmable()
|
||||||
.ok_or(VMError::NotProgrammable(id))?;
|
.ok_or(VMError::NotProgrammable(id))?;
|
||||||
programmable.set_source_code(code)?;
|
programmable.set_source_code(code)?;
|
||||||
@@ -233,12 +234,14 @@ impl VM {
|
|||||||
|
|
||||||
/// Set program code and translate invalid lines to Nop, collecting errors
|
/// Set program code and translate invalid lines to Nop, collecting errors
|
||||||
pub fn set_code_invalid(self: &Rc<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
|
let obj = self
|
||||||
.objects
|
.objects
|
||||||
.borrow()
|
.borrow()
|
||||||
.get(&id)
|
.get(&id)
|
||||||
.ok_or(VMError::UnknownId(id))?
|
.cloned()
|
||||||
.borrow_mut()
|
.ok_or(VMError::UnknownId(id))?;
|
||||||
|
let mut obj_ref = obj.borrow_mut();
|
||||||
|
let programmable = obj_ref
|
||||||
.as_mut_programmable()
|
.as_mut_programmable()
|
||||||
.ok_or(VMError::NotProgrammable(id))?;
|
.ok_or(VMError::NotProgrammable(id))?;
|
||||||
programmable.set_source_code_with_invalid(code);
|
programmable.set_source_code_with_invalid(code);
|
||||||
@@ -255,12 +258,14 @@ impl VM {
|
|||||||
id: u32,
|
id: u32,
|
||||||
advance_ip_on_err: bool,
|
advance_ip_on_err: bool,
|
||||||
) -> Result<(), VMError> {
|
) -> Result<(), VMError> {
|
||||||
let programmable = self
|
let obj = self
|
||||||
.objects
|
.objects
|
||||||
.borrow()
|
.borrow()
|
||||||
.get(&id)
|
.get(&id)
|
||||||
.ok_or(VMError::UnknownId(id))?
|
.cloned()
|
||||||
.borrow_mut()
|
.ok_or(VMError::UnknownId(id))?;
|
||||||
|
let mut obj_ref = obj.borrow_mut();
|
||||||
|
let programmable = obj_ref
|
||||||
.as_mut_programmable()
|
.as_mut_programmable()
|
||||||
.ok_or(VMError::NotProgrammable(id))?;
|
.ok_or(VMError::NotProgrammable(id))?;
|
||||||
self.operation_modified.borrow_mut().clear();
|
self.operation_modified.borrow_mut().clear();
|
||||||
@@ -275,18 +280,20 @@ impl VM {
|
|||||||
id: u32,
|
id: u32,
|
||||||
ignore_errors: bool,
|
ignore_errors: bool,
|
||||||
) -> Result<bool, VMError> {
|
) -> Result<bool, VMError> {
|
||||||
let programmable = self
|
let obj = self
|
||||||
.objects
|
.objects
|
||||||
.borrow()
|
.borrow()
|
||||||
.get(&id)
|
.get(&id)
|
||||||
.ok_or(VMError::UnknownId(id))?
|
.cloned()
|
||||||
.borrow_mut()
|
.ok_or(VMError::UnknownId(id))?;
|
||||||
|
let mut obj_ref = obj.borrow_mut();
|
||||||
|
let programmable = obj_ref
|
||||||
.as_mut_programmable()
|
.as_mut_programmable()
|
||||||
.ok_or(VMError::NotProgrammable(id))?;
|
.ok_or(VMError::NotProgrammable(id))?;
|
||||||
self.operation_modified.borrow_mut().clear();
|
self.operation_modified.borrow_mut().clear();
|
||||||
self.set_modified(id);
|
self.set_modified(id);
|
||||||
for _i in 0..128 {
|
for _i in 0..128 {
|
||||||
if let Err(err) = programmable.step( ignore_errors) {
|
if let Err(err) = programmable.step(ignore_errors) {
|
||||||
if !ignore_errors {
|
if !ignore_errors {
|
||||||
return Err(err.into());
|
return Err(err.into());
|
||||||
}
|
}
|
||||||
@@ -308,12 +315,14 @@ impl VM {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_programmable(self: &Rc<Self>, id: ObjectID) -> Result<bool, VMError> {
|
pub fn reset_programmable(self: &Rc<Self>, id: ObjectID) -> Result<bool, VMError> {
|
||||||
let programmable = self
|
let obj = self
|
||||||
.objects
|
.objects
|
||||||
.borrow()
|
.borrow()
|
||||||
.get(&id)
|
.get(&id)
|
||||||
.ok_or(VMError::UnknownId(id))?
|
.cloned()
|
||||||
.borrow_mut()
|
.ok_or(VMError::UnknownId(id))?;
|
||||||
|
let mut obj_ref = obj.borrow_mut();
|
||||||
|
let programmable = obj_ref
|
||||||
.as_mut_programmable()
|
.as_mut_programmable()
|
||||||
.ok_or(VMError::NotProgrammable(id))?;
|
.ok_or(VMError::NotProgrammable(id))?;
|
||||||
programmable.reset();
|
programmable.reset();
|
||||||
@@ -365,14 +374,15 @@ impl VM {
|
|||||||
.networks
|
.networks
|
||||||
.borrow()
|
.borrow()
|
||||||
.get(&id)
|
.get(&id)
|
||||||
|
.cloned()
|
||||||
.ok_or(ICError::BadNetworkId(id))?;
|
.ok_or(ICError::BadNetworkId(id))?;
|
||||||
if !(0..8).contains(&channel) {
|
if !(0..8).contains(&channel) {
|
||||||
Err(ICError::ChannelIndexOutOfRange(channel))
|
Err(ICError::ChannelIndexOutOfRange(channel))
|
||||||
} else {
|
} else {
|
||||||
let channel_lt = LogicType::from_repr((LogicType::Channel0 as usize + channel) as u16)
|
let channel_lt = LogicType::from_repr((LogicType::Channel0 as usize + channel) as u16)
|
||||||
.expect("channel logictype repr out of range");
|
.expect("channel logictype repr out of range");
|
||||||
let val = network
|
let net_ref = network.borrow();
|
||||||
.borrow_mut()
|
let val = net_ref
|
||||||
.as_network()
|
.as_network()
|
||||||
.expect("non-network network")
|
.expect("non-network network")
|
||||||
.get_logic(channel_lt)?;
|
.get_logic(channel_lt)?;
|
||||||
@@ -390,6 +400,7 @@ impl VM {
|
|||||||
.networks
|
.networks
|
||||||
.borrow()
|
.borrow()
|
||||||
.get(&(id))
|
.get(&(id))
|
||||||
|
.cloned()
|
||||||
.ok_or(ICError::BadNetworkId(id))?;
|
.ok_or(ICError::BadNetworkId(id))?;
|
||||||
if !(0..8).contains(&channel) {
|
if !(0..8).contains(&channel) {
|
||||||
Err(ICError::ChannelIndexOutOfRange(channel))
|
Err(ICError::ChannelIndexOutOfRange(channel))
|
||||||
@@ -425,9 +436,10 @@ impl VM {
|
|||||||
.borrow()
|
.borrow()
|
||||||
.values()
|
.values()
|
||||||
.filter_map(|net| {
|
.filter_map(|net| {
|
||||||
let net_ref = net.borrow().as_network().expect("non-network network");
|
let net_ref = net.borrow();
|
||||||
if net_ref.contains_data(&source) {
|
let net_interface = net_ref.as_network().expect("non-network network");
|
||||||
Some(net_ref.data_visible(&source))
|
if net_interface.contains_data(&source) {
|
||||||
|
Some(net_interface.data_visible(&source))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -441,7 +453,7 @@ impl VM {
|
|||||||
pin: usize,
|
pin: usize,
|
||||||
val: Option<ObjectID>,
|
val: Option<ObjectID>,
|
||||||
) -> Result<bool, VMError> {
|
) -> Result<bool, VMError> {
|
||||||
let Some(obj) = self.objects.borrow().get(&id) else {
|
let Some(obj) = self.objects.borrow().get(&id).cloned() else {
|
||||||
return Err(VMError::UnknownId(id));
|
return Err(VMError::UnknownId(id));
|
||||||
};
|
};
|
||||||
if let Some(other_device) = val {
|
if let Some(other_device) = val {
|
||||||
@@ -452,7 +464,8 @@ impl VM {
|
|||||||
return Err(VMError::DeviceNotVisible(other_device, id));
|
return Err(VMError::DeviceNotVisible(other_device, id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let Some(device) = obj.borrow_mut().as_mut_device() else {
|
let mut obj_ref = obj.borrow_mut();
|
||||||
|
let Some(device) = obj_ref.as_mut_device() else {
|
||||||
return Err(VMError::NotADevice(id));
|
return Err(VMError::NotADevice(id));
|
||||||
};
|
};
|
||||||
let Some(pins) = device.device_pins_mut() else {
|
let Some(pins) = device.device_pins_mut() else {
|
||||||
@@ -472,10 +485,11 @@ impl VM {
|
|||||||
connection: usize,
|
connection: usize,
|
||||||
target_net: Option<ObjectID>,
|
target_net: Option<ObjectID>,
|
||||||
) -> Result<bool, VMError> {
|
) -> Result<bool, VMError> {
|
||||||
let Some(obj) = self.objects.borrow().get(&id) else {
|
let Some(obj) = self.objects.borrow().get(&id).cloned() else {
|
||||||
return Err(VMError::UnknownId(id));
|
return Err(VMError::UnknownId(id));
|
||||||
};
|
};
|
||||||
let Some(device) = obj.borrow_mut().as_mut_device() else {
|
let mut obj_ref = obj.borrow_mut();
|
||||||
|
let Some(device) = obj_ref.as_mut_device() else {
|
||||||
return Err(VMError::NotADevice(id));
|
return Err(VMError::NotADevice(id));
|
||||||
};
|
};
|
||||||
let connections = device.connection_list_mut();
|
let connections = device.connection_list_mut();
|
||||||
@@ -567,10 +581,11 @@ impl VM {
|
|||||||
network_id: ObjectID,
|
network_id: ObjectID,
|
||||||
) -> Result<bool, VMError> {
|
) -> Result<bool, VMError> {
|
||||||
if let Some(network) = self.networks.borrow().get(&network_id) {
|
if let Some(network) = self.networks.borrow().get(&network_id) {
|
||||||
let Some(obj) = self.objects.borrow().get(&id) else {
|
let Some(obj) = self.objects.borrow().get(&id).cloned() else {
|
||||||
return Err(VMError::UnknownId(id));
|
return Err(VMError::UnknownId(id));
|
||||||
};
|
};
|
||||||
let Some(device) = obj.borrow_mut().as_mut_device() else {
|
let mut obj_ref = obj.borrow_mut();
|
||||||
|
let Some(device) = obj_ref.as_mut_device() else {
|
||||||
return Err(VMError::NotADevice(id));
|
return Err(VMError::NotADevice(id));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -629,7 +644,7 @@ impl VM {
|
|||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.as_mut_device()
|
.as_mut_device()
|
||||||
.expect("batch iter yielded non device")
|
.expect("batch iter yielded non device")
|
||||||
.set_slot_logic(typ, index, val, write_readonly)
|
.set_slot_logic(typ, index, val, write_readonly)
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
})
|
})
|
||||||
.try_collect()
|
.try_collect()
|
||||||
@@ -785,35 +800,44 @@ impl VM {
|
|||||||
target: Option<ObjectID>,
|
target: Option<ObjectID>,
|
||||||
quantity: u32,
|
quantity: u32,
|
||||||
) -> Result<Option<ObjectID>, VMError> {
|
) -> Result<Option<ObjectID>, VMError> {
|
||||||
let Some(obj) = self.objects.borrow().get(&id) else {
|
let Some(obj) = self.objects.borrow().get(&id).cloned() else {
|
||||||
return Err(VMError::UnknownId(id));
|
return Err(VMError::UnknownId(id));
|
||||||
};
|
};
|
||||||
let Some(storage) = obj.borrow_mut().as_mut_storage() else {
|
let mut obj_ref = obj.borrow_mut();
|
||||||
|
let Some(storage) = obj_ref.as_mut_storage() else {
|
||||||
return Err(VMError::NotStorage(id));
|
return Err(VMError::NotStorage(id));
|
||||||
};
|
};
|
||||||
let slot = storage
|
let slot = storage
|
||||||
.get_slot_mut(index)
|
.get_slot_mut(index)
|
||||||
.ok_or(ICError::SlotIndexOutOfRange(index as f64))?;
|
.ok_or(ICError::SlotIndexOutOfRange(index as f64))?;
|
||||||
if let Some(target) = target {
|
if let Some(target) = target {
|
||||||
let Some(item_obj) = self.objects.borrow().get(&target) else {
|
if slot.occupant.is_some_and(|occupant| occupant == target) {
|
||||||
return Err(VMError::UnknownId(id));
|
slot.quantity = quantity;
|
||||||
};
|
Ok(None)
|
||||||
let Some(item) = item_obj.borrow_mut().as_mut_item() else {
|
} else {
|
||||||
return Err(VMError::NotAnItem(target));
|
let Some(item_obj) = self.objects.borrow().get(&target).cloned() else {
|
||||||
};
|
return Err(VMError::UnknownId(id));
|
||||||
if let Some(parent_slot_info) = item.get_parent_slot() {
|
};
|
||||||
self.remove_slot_occupant(parent_slot_info.parent, parent_slot_info.slot)?;
|
let mut item_obj_ref = item_obj.borrow_mut();
|
||||||
|
let Some(item) = item_obj_ref.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);
|
||||||
|
slot.quantity = quantity;
|
||||||
|
Ok(last)
|
||||||
}
|
}
|
||||||
item.set_parent_slot(Some(ParentSlotInfo {
|
|
||||||
parent: id,
|
|
||||||
slot: index,
|
|
||||||
}));
|
|
||||||
let last = slot.occupant;
|
|
||||||
slot.occupant = Some(target);
|
|
||||||
Ok(last)
|
|
||||||
} else {
|
} else {
|
||||||
let last = slot.occupant;
|
let last = slot.occupant;
|
||||||
slot.occupant = None;
|
slot.occupant = None;
|
||||||
|
slot.quantity = 0;
|
||||||
Ok(last)
|
Ok(last)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -824,10 +848,11 @@ impl VM {
|
|||||||
id: ObjectID,
|
id: ObjectID,
|
||||||
index: usize,
|
index: usize,
|
||||||
) -> Result<Option<ObjectID>, VMError> {
|
) -> Result<Option<ObjectID>, VMError> {
|
||||||
let Some(obj) = self.objects.borrow().get(&id) else {
|
let Some(obj) = self.objects.borrow().get(&id).cloned() else {
|
||||||
return Err(VMError::UnknownId(id));
|
return Err(VMError::UnknownId(id));
|
||||||
};
|
};
|
||||||
let Some(storage) = obj.borrow_mut().as_mut_storage() else {
|
let mut obj_ref = obj.borrow_mut();
|
||||||
|
let Some(storage) = obj_ref.as_mut_storage() else {
|
||||||
return Err(VMError::NotStorage(id));
|
return Err(VMError::NotStorage(id));
|
||||||
};
|
};
|
||||||
let slot = storage
|
let slot = storage
|
||||||
@@ -845,7 +870,7 @@ impl VM {
|
|||||||
.objects
|
.objects
|
||||||
.borrow()
|
.borrow()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(obj_id, obj)| {
|
.filter_map(|(_obj_id, obj)| {
|
||||||
if obj
|
if obj
|
||||||
.borrow()
|
.borrow()
|
||||||
.as_item()
|
.as_item()
|
||||||
@@ -929,21 +954,19 @@ impl VM {
|
|||||||
.extend(transaction.wireless_receivers);
|
.extend(transaction.wireless_receivers);
|
||||||
|
|
||||||
for (net_id, trans_net) in transaction.networks.into_iter() {
|
for (net_id, trans_net) in transaction.networks.into_iter() {
|
||||||
let net = self
|
let networks_ref = self.networks.borrow();
|
||||||
.networks
|
let net = networks_ref.get(&net_id).expect(&format!(
|
||||||
.borrow()
|
"desync between vm and transaction networks: {net_id}"
|
||||||
.get(&net_id)
|
));
|
||||||
.expect(&format!(
|
let mut net_ref = net.borrow_mut();
|
||||||
"desync between vm and transaction networks: {net_id}"
|
let net_interface = net_ref
|
||||||
))
|
|
||||||
.borrow_mut()
|
|
||||||
.as_mut_network()
|
.as_mut_network()
|
||||||
.expect(&format!("non network network: {net_id}"));
|
.expect(&format!("non network network: {net_id}"));
|
||||||
for id in trans_net.devices {
|
for id in trans_net.devices {
|
||||||
net.add_data(id);
|
net_interface.add_data(id);
|
||||||
}
|
}
|
||||||
for id in trans_net.power_only {
|
for id in trans_net.power_only {
|
||||||
net.add_power(id);
|
net_interface.add_power(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1025,16 +1048,16 @@ impl VMTransaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(w_logicable) = obj.borrow().as_wireless_transmit() {
|
if let Some(_w_logicable) = obj.borrow().as_wireless_transmit() {
|
||||||
self.wireless_transmitters.push(obj_id);
|
self.wireless_transmitters.push(obj_id);
|
||||||
}
|
}
|
||||||
if let Some(r_logicable) = obj.borrow().as_wireless_receive() {
|
if let Some(_r_logicable) = obj.borrow().as_wireless_receive() {
|
||||||
self.wireless_receivers.push(obj_id);
|
self.wireless_receivers.push(obj_id);
|
||||||
}
|
}
|
||||||
if let Some(circuit_holder) = obj.borrow().as_circuit_holder() {
|
if let Some(_circuit_holder) = obj.borrow().as_circuit_holder() {
|
||||||
self.circuit_holders.push(obj_id);
|
self.circuit_holders.push(obj_id);
|
||||||
}
|
}
|
||||||
if let Some(programmable) = obj.borrow().as_programmable() {
|
if let Some(_programmable) = obj.borrow().as_programmable() {
|
||||||
self.program_holders.push(obj_id);
|
self.program_holders.push(obj_id);
|
||||||
}
|
}
|
||||||
if let Some(device) = obj.borrow_mut().as_mut_device() {
|
if let Some(device) = obj.borrow_mut().as_mut_device() {
|
||||||
|
|||||||
@@ -75,25 +75,25 @@ impl InstOperand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ident(&self) -> Result<Identifier, ICError> {
|
pub fn as_ident(&self) -> Result<Identifier, ICError> {
|
||||||
let &Operand::Identifier(ident) = &self.operand else {
|
let Operand::Identifier(ident) = &self.operand else {
|
||||||
return Err(ICError::IncorrectOperandType {
|
return Err(ICError::IncorrectOperandType {
|
||||||
inst: self.inst,
|
inst: self.inst,
|
||||||
index: self.index,
|
index: self.index,
|
||||||
desired: "Name".to_owned(),
|
desired: "Name".to_owned(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Ok(ident)
|
Ok(ident.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_number(&self) -> Result<Number, ICError> {
|
pub fn as_number(&self) -> Result<Number, ICError> {
|
||||||
let &Operand::Number(num) = &self.operand else {
|
let Operand::Number(num) = &self.operand else {
|
||||||
return Err(ICError::IncorrectOperandType {
|
return Err(ICError::IncorrectOperandType {
|
||||||
inst: self.inst,
|
inst: self.inst,
|
||||||
index: self.index,
|
index: self.index,
|
||||||
desired: "Number".to_owned(),
|
desired: "Number".to_owned(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Ok(num)
|
Ok(num.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_aliasable(&self) -> Result<Operand, ICError> {
|
pub fn as_aliasable(&self) -> Result<Operand, ICError> {
|
||||||
@@ -287,7 +287,7 @@ impl InstOperand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn translate_alias<IC: IntegratedCircuit>(&self, ic: &IC) -> Operand {
|
pub fn translate_alias<IC: IntegratedCircuit>(&self, ic: &IC) -> Operand {
|
||||||
match self.operand {
|
match &self.operand {
|
||||||
Operand::Identifier(id) | Operand::Type { identifier: id, .. } => {
|
Operand::Identifier(id) | Operand::Type { identifier: id, .. } => {
|
||||||
if let Some(alias) = ic.get_aliases().get(&id.name) {
|
if let Some(alias) = ic.get_aliases().get(&id.name) {
|
||||||
alias.clone()
|
alias.clone()
|
||||||
@@ -299,7 +299,7 @@ impl InstOperand {
|
|||||||
self.operand.clone()
|
self.operand.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => self.clone(),
|
_ => self.operand.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,4 +123,5 @@ pub struct Slot {
|
|||||||
pub readable_logic: Vec<LogicSlotType>,
|
pub readable_logic: Vec<LogicSlotType>,
|
||||||
pub writeable_logic: Vec<LogicSlotType>,
|
pub writeable_logic: Vec<LogicSlotType>,
|
||||||
pub occupant: Option<ObjectID>,
|
pub occupant: Option<ObjectID>,
|
||||||
|
pub quantity: u32,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,18 +102,24 @@ macro_rules! GWDevice {
|
|||||||
fn device_info(&self) -> &DeviceInfo {
|
fn device_info(&self) -> &DeviceInfo {
|
||||||
&self.device_info
|
&self.device_info
|
||||||
}
|
}
|
||||||
fn device_connections(&self) -> &[Connection] {
|
fn connections(&self) -> &[Connection] {
|
||||||
self.connections.as_slice()
|
self.connections.as_slice()
|
||||||
}
|
}
|
||||||
fn device_connections_mut(&mut self) -> &mut [Connection] {
|
fn connections_mut(&mut self) -> &mut [Connection] {
|
||||||
self.connections.as_mut_slice()
|
self.connections.as_mut_slice()
|
||||||
}
|
}
|
||||||
fn device_pins(&self) -> Option<&[Option<ObjectID>]> {
|
fn pins(&self) -> Option<&[Option<ObjectID>]> {
|
||||||
self.pins.as_ref().map(|pins| pins.as_slice())
|
self.pins.as_ref().map(|pins| pins.as_slice())
|
||||||
}
|
}
|
||||||
fn device_pins_mut(&mut self) -> Option<&mut [Option<ObjectID>]> {
|
fn pins_mut(&mut self) -> Option<&mut [Option<ObjectID>]> {
|
||||||
self.pins.as_mut().map(|pins| pins.as_mut_slice())
|
self.pins.as_mut().map(|pins| pins.as_mut_slice())
|
||||||
}
|
}
|
||||||
|
fn reagents(&self) -> Option<&BTreeMap<i32, f64>> {
|
||||||
|
self.reagents.as_ref()
|
||||||
|
}
|
||||||
|
fn reagents_mut(&mut self) -> &mut Option<BTreeMap<i32, f64>> {
|
||||||
|
&mut self.reagents
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -136,6 +142,12 @@ macro_rules! GWItem {
|
|||||||
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>) {
|
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>) {
|
||||||
self.parent_slot = info;
|
self.parent_slot = info;
|
||||||
}
|
}
|
||||||
|
fn damage(&self) -> &Option<f32> {
|
||||||
|
&self.damage
|
||||||
|
}
|
||||||
|
fn damage_mut(&mut self) -> &mut Option<f32> {
|
||||||
|
&mut self.damage
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ pub struct GenericLogicableDevice {
|
|||||||
pub device_info: DeviceInfo,
|
pub device_info: DeviceInfo,
|
||||||
pub connections: Vec<Connection>,
|
pub connections: Vec<Connection>,
|
||||||
pub pins: Option<Vec<Option<ObjectID>>>,
|
pub pins: Option<Vec<Option<ObjectID>>>,
|
||||||
|
pub reagents: Option<BTreeMap<i32, f64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(ObjectInterface!, GWStructure!, GWStorage!, GWLogicable!, GWDevice!, GWMemoryReadable!, GWMemoryWritable!)]
|
#[derive(ObjectInterface!, GWStructure!, GWStorage!, GWLogicable!, GWDevice!, GWMemoryReadable!, GWMemoryWritable!)]
|
||||||
@@ -100,6 +101,7 @@ pub struct GenericLogicableDeviceMemoryReadable {
|
|||||||
pub device_info: DeviceInfo,
|
pub device_info: DeviceInfo,
|
||||||
pub connections: Vec<Connection>,
|
pub connections: Vec<Connection>,
|
||||||
pub pins: Option<Vec<Option<ObjectID>>>,
|
pub pins: Option<Vec<Option<ObjectID>>>,
|
||||||
|
pub reagents: Option<BTreeMap<i32, f64>>,
|
||||||
pub memory: Vec<f64>,
|
pub memory: Vec<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,6 +123,7 @@ pub struct GenericLogicableDeviceMemoryReadWriteable {
|
|||||||
pub device_info: DeviceInfo,
|
pub device_info: DeviceInfo,
|
||||||
pub connections: Vec<Connection>,
|
pub connections: Vec<Connection>,
|
||||||
pub pins: Option<Vec<Option<ObjectID>>>,
|
pub pins: Option<Vec<Option<ObjectID>>>,
|
||||||
|
pub reagents: Option<BTreeMap<i32, f64>>,
|
||||||
pub memory: Vec<f64>,
|
pub memory: Vec<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +140,7 @@ pub struct GenericItem {
|
|||||||
pub vm: Rc<VM>,
|
pub vm: Rc<VM>,
|
||||||
pub item_info: ItemInfo,
|
pub item_info: ItemInfo,
|
||||||
pub parent_slot: Option<ParentSlotInfo>,
|
pub parent_slot: Option<ParentSlotInfo>,
|
||||||
|
pub damage: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(ObjectInterface!, GWItem!, GWStorage! )]
|
#[derive(ObjectInterface!, GWItem!, GWStorage! )]
|
||||||
@@ -152,6 +156,7 @@ pub struct GenericItemStorage {
|
|||||||
pub vm: Rc<VM>,
|
pub vm: Rc<VM>,
|
||||||
pub item_info: ItemInfo,
|
pub item_info: ItemInfo,
|
||||||
pub parent_slot: Option<ParentSlotInfo>,
|
pub parent_slot: Option<ParentSlotInfo>,
|
||||||
|
pub damage: Option<f32>,
|
||||||
pub slots: Vec<Slot>,
|
pub slots: Vec<Slot>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,6 +173,7 @@ pub struct GenericItemLogicable {
|
|||||||
pub vm: Rc<VM>,
|
pub vm: Rc<VM>,
|
||||||
pub item_info: ItemInfo,
|
pub item_info: ItemInfo,
|
||||||
pub parent_slot: Option<ParentSlotInfo>,
|
pub parent_slot: Option<ParentSlotInfo>,
|
||||||
|
pub damage: Option<f32>,
|
||||||
pub slots: Vec<Slot>,
|
pub slots: Vec<Slot>,
|
||||||
pub fields: BTreeMap<LogicType, LogicField>,
|
pub fields: BTreeMap<LogicType, LogicField>,
|
||||||
pub modes: Option<BTreeMap<u32, String>>,
|
pub modes: Option<BTreeMap<u32, String>>,
|
||||||
@@ -186,6 +192,7 @@ pub struct GenericItemLogicableMemoryReadable {
|
|||||||
pub vm: Rc<VM>,
|
pub vm: Rc<VM>,
|
||||||
pub item_info: ItemInfo,
|
pub item_info: ItemInfo,
|
||||||
pub parent_slot: Option<ParentSlotInfo>,
|
pub parent_slot: Option<ParentSlotInfo>,
|
||||||
|
pub damage: Option<f32>,
|
||||||
pub slots: Vec<Slot>,
|
pub slots: Vec<Slot>,
|
||||||
pub fields: BTreeMap<LogicType, LogicField>,
|
pub fields: BTreeMap<LogicType, LogicField>,
|
||||||
pub modes: Option<BTreeMap<u32, String>>,
|
pub modes: Option<BTreeMap<u32, String>>,
|
||||||
@@ -205,6 +212,7 @@ pub struct GenericItemLogicableMemoryReadWriteable {
|
|||||||
pub vm: Rc<VM>,
|
pub vm: Rc<VM>,
|
||||||
pub item_info: ItemInfo,
|
pub item_info: ItemInfo,
|
||||||
pub parent_slot: Option<ParentSlotInfo>,
|
pub parent_slot: Option<ParentSlotInfo>,
|
||||||
|
pub damage: Option<f32>,
|
||||||
pub slots: Vec<Slot>,
|
pub slots: Vec<Slot>,
|
||||||
pub fields: BTreeMap<LogicType, LogicField>,
|
pub fields: BTreeMap<LogicType, LogicField>,
|
||||||
pub modes: Option<BTreeMap<u32, String>>,
|
pub modes: Option<BTreeMap<u32, String>>,
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ use crate::{
|
|||||||
traits::*,
|
traits::*,
|
||||||
LogicField, MemoryAccess, ObjectID, Slot,
|
LogicField, MemoryAccess, ObjectID, Slot,
|
||||||
},
|
},
|
||||||
VM,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::{collections::BTreeMap, usize};
|
use std::{collections::BTreeMap, usize};
|
||||||
@@ -120,28 +119,165 @@ impl<T: GWLogicable + Object> Logicable for T {
|
|||||||
if index < 0.0 {
|
if index < 0.0 {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
|
use LogicSlotType::*;
|
||||||
|
if matches!(
|
||||||
|
slt,
|
||||||
|
Occupied
|
||||||
|
| OccupantHash
|
||||||
|
| Quantity
|
||||||
|
| Class
|
||||||
|
| MaxQuantity
|
||||||
|
| PrefabHash
|
||||||
|
| SortingClass
|
||||||
|
| ReferenceId
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
self.get_slot(index as usize)
|
self.get_slot(index as usize)
|
||||||
.map(|slot| slot.readable_logic.contains(&slt))
|
.map(|slot| slot.readable_logic.contains(&slt))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_slot_logic(&self, slt: LogicSlotType, index: f64, _vm: &VM) -> Result<f64, LogicError> {
|
fn get_slot_logic(&self, slt: LogicSlotType, index: f64) -> Result<f64, LogicError> {
|
||||||
if index < 0.0 {
|
if index < 0.0 {
|
||||||
return Err(LogicError::SlotIndexOutOfRange(index, self.slots_count()));
|
return Err(LogicError::SlotIndexOutOfRange(index, self.slots_count()));
|
||||||
}
|
}
|
||||||
self.get_slot(index as usize)
|
self.get_slot(index as usize)
|
||||||
.ok_or_else(|| LogicError::SlotIndexOutOfRange(index, self.slots_count()))
|
.ok_or_else(|| LogicError::SlotIndexOutOfRange(index, self.slots_count()))
|
||||||
.and_then(|slot| {
|
.and_then(|slot| {
|
||||||
if slot.readable_logic.contains(&slt) {
|
use LogicSlotType::*;
|
||||||
match slot.occupant {
|
let occupant = slot.occupant.and_then(|id| self.get_vm().get_object(id));
|
||||||
Some(_id) => {
|
match slt {
|
||||||
// FIXME: impliment by accessing VM to get occupant
|
Occupied => {
|
||||||
|
if slot.occupant.is_some() {
|
||||||
|
Ok(1.0)
|
||||||
|
} else {
|
||||||
Ok(0.0)
|
Ok(0.0)
|
||||||
}
|
}
|
||||||
None => Ok(0.0),
|
|
||||||
}
|
}
|
||||||
} else {
|
Quantity => {
|
||||||
Err(LogicError::CantSlotRead(slt, index))
|
if slot.occupant.is_some() {
|
||||||
|
Ok(slot.quantity as f64)
|
||||||
|
} else {
|
||||||
|
Ok(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Class => {
|
||||||
|
if slot.occupant.is_some() {
|
||||||
|
Ok(slot.typ as i32 as f64)
|
||||||
|
} else {
|
||||||
|
Ok(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OccupantHash | PrefabHash => {
|
||||||
|
if let Some(occupant) = occupant {
|
||||||
|
Ok(occupant.borrow().get_prefab().hash as f64)
|
||||||
|
} else {
|
||||||
|
Ok(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MaxQuantity => {
|
||||||
|
if let Some(occupant) = occupant {
|
||||||
|
Ok(occupant
|
||||||
|
.borrow()
|
||||||
|
.as_item()
|
||||||
|
.map(|item| item.max_quantity() as f64)
|
||||||
|
.ok_or(LogicError::CantSlotRead(slt, index))?)
|
||||||
|
} else {
|
||||||
|
Ok(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SortingClass => {
|
||||||
|
if let Some(occupant) = occupant {
|
||||||
|
Ok(occupant
|
||||||
|
.borrow()
|
||||||
|
.as_item()
|
||||||
|
.map(|item| item.sorting_class() as i32 as f64)
|
||||||
|
.ok_or(LogicError::CantSlotRead(slt, index))?)
|
||||||
|
} else {
|
||||||
|
Ok(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReferenceId => {
|
||||||
|
if let Some(occupant) = occupant {
|
||||||
|
Ok(occupant.borrow().get_id() as f64)
|
||||||
|
} else {
|
||||||
|
Ok(0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slt => {
|
||||||
|
if slot.readable_logic.contains(&slt) {
|
||||||
|
if let Some(occupant) = occupant {
|
||||||
|
let occupant_ref = occupant.borrow();
|
||||||
|
let logicable = occupant_ref
|
||||||
|
.as_logicable()
|
||||||
|
.ok_or(LogicError::CantSlotRead(slt, index))?;
|
||||||
|
|
||||||
|
match slt {
|
||||||
|
Occupied | Quantity | Class | OccupantHash | PrefabHash
|
||||||
|
| MaxQuantity | SortingClass | ReferenceId => Ok(0.0), // covered above
|
||||||
|
LineNumber => logicable.get_logic(LogicType::LineNumber),
|
||||||
|
|
||||||
|
Charge => logicable.get_logic(LogicType::Charge),
|
||||||
|
ChargeRatio => logicable
|
||||||
|
.as_chargeable()
|
||||||
|
.map(|chargeable| chargeable.get_charge() as f64)
|
||||||
|
.ok_or(LogicError::CantSlotRead(slt, index)),
|
||||||
|
Open => logicable.get_logic(LogicType::Open),
|
||||||
|
On => logicable.get_logic(LogicType::Open),
|
||||||
|
Lock => logicable.get_logic(LogicType::Lock),
|
||||||
|
FilterType => Ok(logicable
|
||||||
|
.as_item()
|
||||||
|
.and_then(|item| item.filter_type())
|
||||||
|
.ok_or(LogicError::CantSlotRead(slt, index))?
|
||||||
|
as i32
|
||||||
|
as f64),
|
||||||
|
Damage => logicable
|
||||||
|
.as_item()
|
||||||
|
.map(|item| item.get_damage() as f64)
|
||||||
|
.ok_or(LogicError::CantSlotRead(slt, index)),
|
||||||
|
Volume => logicable.get_logic(LogicType::Volume),
|
||||||
|
Pressure => logicable.get_logic(LogicType::Pressure),
|
||||||
|
PressureAir => logicable
|
||||||
|
.as_suit()
|
||||||
|
.map(|suit| suit.pressure_air())
|
||||||
|
.ok_or(LogicError::CantSlotRead(slt, index)),
|
||||||
|
PressureWaste => logicable
|
||||||
|
.as_suit()
|
||||||
|
.map(|suit| suit.pressure_waste())
|
||||||
|
.ok_or(LogicError::CantSlotRead(slt, index)),
|
||||||
|
Temperature => logicable.get_logic(LogicType::Temperature),
|
||||||
|
Seeding => logicable
|
||||||
|
.as_plant()
|
||||||
|
.map(|plant| plant.is_seeding() as i32 as f64)
|
||||||
|
.ok_or(LogicError::CantSlotRead(slt, index)),
|
||||||
|
Mature => logicable
|
||||||
|
.as_plant()
|
||||||
|
.map(|plant| plant.is_mature() as i32 as f64)
|
||||||
|
.ok_or(LogicError::CantSlotRead(slt, index)),
|
||||||
|
Growth => logicable
|
||||||
|
.as_plant()
|
||||||
|
.map(|plant| plant.get_growth())
|
||||||
|
.ok_or(LogicError::CantSlotRead(slt, index)),
|
||||||
|
Health => logicable
|
||||||
|
.as_plant()
|
||||||
|
.map(|plant| plant.get_health())
|
||||||
|
.ok_or(LogicError::CantSlotRead(slt, index)),
|
||||||
|
Efficiency => logicable
|
||||||
|
.as_plant()
|
||||||
|
.map(|plant| plant.get_health())
|
||||||
|
.ok_or(LogicError::CantSlotRead(slt, index)),
|
||||||
|
|
||||||
|
// defaults
|
||||||
|
None => Ok(0.0),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(0.0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(LogicError::CantSlotRead(slt, index))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -204,16 +340,18 @@ impl<T: GWMemoryWritable + MemoryReadable + Object> MemoryWritable for T {
|
|||||||
|
|
||||||
pub trait GWDevice: GWLogicable + Logicable {
|
pub trait GWDevice: GWLogicable + Logicable {
|
||||||
fn device_info(&self) -> &DeviceInfo;
|
fn device_info(&self) -> &DeviceInfo;
|
||||||
fn device_connections(&self) -> &[Connection];
|
fn connections(&self) -> &[Connection];
|
||||||
fn device_connections_mut(&mut self) -> &mut [Connection];
|
fn connections_mut(&mut self) -> &mut [Connection];
|
||||||
fn device_pins(&self) -> Option<&[Option<ObjectID>]>;
|
fn pins(&self) -> Option<&[Option<ObjectID>]>;
|
||||||
fn device_pins_mut(&mut self) -> Option<&mut [Option<ObjectID>]>;
|
fn pins_mut(&mut self) -> Option<&mut [Option<ObjectID>]>;
|
||||||
|
fn reagents(&self) -> Option<&BTreeMap<i32, f64>>;
|
||||||
|
fn reagents_mut(&mut self) -> &mut Option<BTreeMap<i32, f64>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GWDevice + Object> Device for T {
|
impl<T: GWDevice + GWStorage + Object> Device for T {
|
||||||
fn can_slot_logic_write(&self, slt: LogicSlotType, index: f64) -> bool {
|
fn can_slot_logic_write(&self, slt: LogicSlotType, index: f64) -> bool {
|
||||||
if index < 0.0 {
|
if index < 0.0 {
|
||||||
return false;
|
false
|
||||||
} else {
|
} else {
|
||||||
self.get_slot(index as usize)
|
self.get_slot(index as usize)
|
||||||
.map(|slot| slot.writeable_logic.contains(&slt))
|
.map(|slot| slot.writeable_logic.contains(&slt))
|
||||||
@@ -225,22 +363,47 @@ impl<T: GWDevice + Object> Device for T {
|
|||||||
slt: LogicSlotType,
|
slt: LogicSlotType,
|
||||||
index: f64,
|
index: f64,
|
||||||
value: f64,
|
value: f64,
|
||||||
vm: &VM,
|
|
||||||
force: bool,
|
force: bool,
|
||||||
) -> Result<(), LogicError> {
|
) -> Result<(), LogicError> {
|
||||||
|
let slots_count = self.slots_count();
|
||||||
if index < 0.0 {
|
if index < 0.0 {
|
||||||
return Err(LogicError::SlotIndexOutOfRange(index, self.slots_count()));
|
return Err(LogicError::SlotIndexOutOfRange(index, slots_count));
|
||||||
}
|
}
|
||||||
|
use LogicSlotType::*;
|
||||||
|
let vm = self.get_vm().clone();
|
||||||
|
|
||||||
self.get_slot_mut(index as usize)
|
self.get_slot_mut(index as usize)
|
||||||
.ok_or_else(|| LogicError::SlotIndexOutOfRange(index, self.slots_count()))
|
.ok_or(LogicError::SlotIndexOutOfRange(index, slots_count))
|
||||||
.and_then(|slot| {
|
.and_then(|slot| {
|
||||||
|
// special case, update slot quantity if >= 1
|
||||||
|
if slt == Quantity && force && value >= 1.0 {
|
||||||
|
slot.quantity = value as u32;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
if slot.writeable_logic.contains(&slt) {
|
if slot.writeable_logic.contains(&slt) {
|
||||||
match slot.occupant {
|
let occupant = slot.occupant.and_then(|id| vm.get_object(id));
|
||||||
Some(_id) => {
|
if let Some(occupant) = occupant {
|
||||||
// FIXME: impliment by accessing VM to get occupant
|
let mut occupant_ref = occupant.borrow_mut();
|
||||||
Ok(())
|
let logicable = occupant_ref
|
||||||
|
.as_mut_logicable()
|
||||||
|
.ok_or(LogicError::CantSlotWrite(slt, index))?;
|
||||||
|
match slt {
|
||||||
|
Open => logicable.set_logic(LogicType::Open, value, force),
|
||||||
|
On => logicable.set_logic(LogicType::On, value, force),
|
||||||
|
Lock => logicable.set_logic(LogicType::On, value, force),
|
||||||
|
// no other values are known to be writeable
|
||||||
|
Damage if force => {
|
||||||
|
logicable
|
||||||
|
.as_mut_item()
|
||||||
|
.map(|item| item.set_damage(value as f32))
|
||||||
|
.ok_or(LogicError::CantSlotWrite(slt, index))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => Ok(()),
|
||||||
}
|
}
|
||||||
None => Ok(()),
|
} else {
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(LogicError::CantSlotWrite(slt, index))
|
Err(LogicError::CantSlotWrite(slt, index))
|
||||||
@@ -248,16 +411,16 @@ impl<T: GWDevice + Object> Device for T {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn connection_list(&self) -> &[crate::network::Connection] {
|
fn connection_list(&self) -> &[crate::network::Connection] {
|
||||||
self.device_connections()
|
self.connections()
|
||||||
}
|
}
|
||||||
fn connection_list_mut(&mut self) -> &mut [Connection] {
|
fn connection_list_mut(&mut self) -> &mut [Connection] {
|
||||||
self.device_connections_mut()
|
self.connections_mut()
|
||||||
}
|
}
|
||||||
fn device_pins(&self) -> Option<&[Option<ObjectID>]> {
|
fn device_pins(&self) -> Option<&[Option<ObjectID>]> {
|
||||||
self.device_pins()
|
self.pins()
|
||||||
}
|
}
|
||||||
fn device_pins_mut(&self) -> Option<&mut [Option<ObjectID>]> {
|
fn device_pins_mut(&mut self) -> Option<&mut [Option<ObjectID>]> {
|
||||||
self.device_pins_mut()
|
self.pins_mut()
|
||||||
}
|
}
|
||||||
fn has_reagents(&self) -> bool {
|
fn has_reagents(&self) -> bool {
|
||||||
self.device_info().has_reagents
|
self.device_info().has_reagents
|
||||||
@@ -283,12 +446,36 @@ impl<T: GWDevice + Object> Device for T {
|
|||||||
fn has_atmosphere(&self) -> bool {
|
fn has_atmosphere(&self) -> bool {
|
||||||
self.device_info().has_atmosphere
|
self.device_info().has_atmosphere
|
||||||
}
|
}
|
||||||
|
fn get_reagents(&self) -> Vec<(i32, f64)> {
|
||||||
|
self.reagents()
|
||||||
|
.map(|reagents| {
|
||||||
|
reagents
|
||||||
|
.iter()
|
||||||
|
.map(|(hash, quant)| (*hash, *quant))
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
fn set_reagents(&mut self, reagents: &[(i32, f64)]) {
|
||||||
|
let reagents_ref = self.reagents_mut();
|
||||||
|
*reagents_ref = Some(reagents.iter().copied().collect());
|
||||||
|
}
|
||||||
|
fn add_reagents(&mut self, reagents: &[(i32, f64)]) {
|
||||||
|
let reagents_ref = self.reagents_mut();
|
||||||
|
if let Some(ref mut reagents_ref) = reagents_ref {
|
||||||
|
reagents_ref.extend(reagents.iter().map(|(hash, quant)| (hash, quant)));
|
||||||
|
} else {
|
||||||
|
*reagents_ref = Some(reagents.iter().copied().collect());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GWItem {
|
pub trait GWItem {
|
||||||
fn item_info(&self) -> &ItemInfo;
|
fn item_info(&self) -> &ItemInfo;
|
||||||
fn parent_slot(&self) -> Option<ParentSlotInfo>;
|
fn parent_slot(&self) -> Option<ParentSlotInfo>;
|
||||||
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>);
|
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>);
|
||||||
|
fn damage(&self) -> &Option<f32>;
|
||||||
|
fn damage_mut(&mut self) -> &mut Option<f32>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GWItem + Object> Item for T {
|
impl<T: GWItem + Object> Item for T {
|
||||||
@@ -319,6 +506,12 @@ impl<T: GWItem + Object> Item for T {
|
|||||||
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>) {
|
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>) {
|
||||||
self.set_parent_slot(info);
|
self.set_parent_slot(info);
|
||||||
}
|
}
|
||||||
|
fn get_damage(&self) -> f32 {
|
||||||
|
self.damage().unwrap_or(0.0)
|
||||||
|
}
|
||||||
|
fn set_damage(&mut self, damage: f32) {
|
||||||
|
self.damage_mut().replace(damage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GWCircuitHolder: Logicable {}
|
pub trait GWCircuitHolder: Logicable {}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use crate::{
|
|||||||
errors::{LogicError, MemoryError},
|
errors::{LogicError, MemoryError},
|
||||||
macros::ObjectInterface,
|
macros::ObjectInterface,
|
||||||
traits::*,
|
traits::*,
|
||||||
LogicField, MemoryAccess, Name, ObjectID, Slot,
|
LogicField, MemoryAccess, Name, ObjectID, Slot, VMObject,
|
||||||
},
|
},
|
||||||
VM,
|
VM,
|
||||||
},
|
},
|
||||||
@@ -48,6 +48,7 @@ pub struct ItemIntegratedCircuit10 {
|
|||||||
pub state: ICState,
|
pub state: ICState,
|
||||||
pub code: String,
|
pub code: String,
|
||||||
pub program: Program,
|
pub program: Program,
|
||||||
|
pub damage: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item for ItemIntegratedCircuit10 {
|
impl Item for ItemIntegratedCircuit10 {
|
||||||
@@ -78,16 +79,22 @@ impl Item for ItemIntegratedCircuit10 {
|
|||||||
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>) {
|
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>) {
|
||||||
self.parent_slot = info;
|
self.parent_slot = info;
|
||||||
}
|
}
|
||||||
|
fn get_damage(&self) -> f32 {
|
||||||
|
self.damage
|
||||||
|
}
|
||||||
|
fn set_damage(&mut self, damage: f32) {
|
||||||
|
self.damage = damage;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Storage for ItemIntegratedCircuit10 {
|
impl Storage for ItemIntegratedCircuit10 {
|
||||||
fn slots_count(&self) -> usize {
|
fn slots_count(&self) -> usize {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
fn get_slot(&self, index: usize) -> Option<&Slot> {
|
fn get_slot(&self, _index: usize) -> Option<&Slot> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
fn get_slot_mut(&mut self, index: usize) -> Option<&mut Slot> {
|
fn get_slot_mut(&mut self, _index: usize) -> Option<&mut Slot> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
fn get_slots(&self) -> &[Slot] {
|
fn get_slots(&self) -> &[Slot] {
|
||||||
@@ -158,10 +165,10 @@ impl Logicable for ItemIntegratedCircuit10 {
|
|||||||
_ => Err(LogicError::CantWrite(lt)),
|
_ => Err(LogicError::CantWrite(lt)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn can_slot_logic_read(&self, slt: LogicSlotType, index: f64) -> bool {
|
fn can_slot_logic_read(&self, _slt: LogicSlotType,_indexx: f64) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
fn get_slot_logic(&self, slt: LogicSlotType, index: f64) -> Result<f64, LogicError> {
|
fn get_slot_logic(&self, _slt: LogicSlotType, index: f64) -> Result<f64, LogicError> {
|
||||||
return Err(LogicError::SlotIndexOutOfRange(index, self.slots_count()));
|
return Err(LogicError::SlotIndexOutOfRange(index, self.slots_count()));
|
||||||
}
|
}
|
||||||
fn valid_logic_types(&self) -> Vec<LogicType> {
|
fn valid_logic_types(&self) -> Vec<LogicType> {
|
||||||
@@ -226,14 +233,9 @@ impl SourceCode for ItemIntegratedCircuit10 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IntegratedCircuit for ItemIntegratedCircuit10 {
|
impl IntegratedCircuit for ItemIntegratedCircuit10 {
|
||||||
fn get_circuit_holder(&self) -> Option<CircuitHolderRef> {
|
fn get_circuit_holder(&self) -> Option<VMObject> {
|
||||||
self.get_parent_slot()
|
self.get_parent_slot()
|
||||||
.map(|parent_slot| {
|
.map(|parent_slot| self.get_vm().get_object(parent_slot.parent))
|
||||||
self.get_vm()
|
|
||||||
.get_object(parent_slot.parent)
|
|
||||||
.map(|obj| obj.borrow().as_circuit_holder())
|
|
||||||
.flatten()
|
|
||||||
})
|
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
fn get_instruction_pointer(&self) -> f64 {
|
fn get_instruction_pointer(&self) -> f64 {
|
||||||
@@ -332,7 +334,7 @@ impl IntegratedCircuit for ItemIntegratedCircuit10 {
|
|||||||
Ok(val)
|
Ok(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn put_stack(&self, addr: f64, val: f64) -> Result<f64, ICError> {
|
fn put_stack(&mut self, addr: f64, val: f64) -> Result<f64, ICError> {
|
||||||
let sp = addr.round() as i32;
|
let sp = addr.round() as i32;
|
||||||
if !(0..(self.memory.len() as i32)).contains(&sp) {
|
if !(0..(self.memory.len() as i32)).contains(&sp) {
|
||||||
Err(ICError::StackIndexOutOfRange(addr))
|
Err(ICError::StackIndexOutOfRange(addr))
|
||||||
@@ -358,7 +360,7 @@ impl IntegratedCircuit for ItemIntegratedCircuit10 {
|
|||||||
&self.program.labels
|
&self.program.labels
|
||||||
}
|
}
|
||||||
fn get_state(&self) -> crate::interpreter::ICState {
|
fn get_state(&self) -> crate::interpreter::ICState {
|
||||||
self.state
|
self.state.clone()
|
||||||
}
|
}
|
||||||
fn set_state(&mut self, state: crate::interpreter::ICState) {
|
fn set_state(&mut self, state: crate::interpreter::ICState) {
|
||||||
self.state = state;
|
self.state = state;
|
||||||
@@ -369,7 +371,10 @@ impl IC10Marker for ItemIntegratedCircuit10 {}
|
|||||||
|
|
||||||
impl Programmable for ItemIntegratedCircuit10 {
|
impl Programmable for ItemIntegratedCircuit10 {
|
||||||
fn step(&mut self, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError> {
|
fn step(&mut self, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError> {
|
||||||
if matches!(&self.state, ICState::HasCaughtFire | ICState::Error(_)) {
|
if matches!(&self.state, ICState::HasCaughtFire ) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if matches!(&self.state, ICState::Error(_)) && !advance_ip_on_err {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if let ICState::Sleep(then, sleep_for) = &self.state {
|
if let ICState::Sleep(then, sleep_for) = &self.state {
|
||||||
@@ -395,7 +400,7 @@ impl Programmable for ItemIntegratedCircuit10 {
|
|||||||
}
|
}
|
||||||
self.next_ip = self.ip + 1;
|
self.next_ip = self.ip + 1;
|
||||||
self.state = ICState::Running;
|
self.state = ICState::Running;
|
||||||
let line = self.program.get_line(self.ip)?;
|
let line = self.program.get_line(self.ip)?.clone();
|
||||||
let operands = &line.operands;
|
let operands = &line.operands;
|
||||||
let instruction = line.instruction;
|
let instruction = line.instruction;
|
||||||
instruction.execute(self, operands)?;
|
instruction.execute(self, operands)?;
|
||||||
@@ -405,6 +410,9 @@ impl Programmable for ItemIntegratedCircuit10 {
|
|||||||
}
|
}
|
||||||
self.get_circuit_holder()
|
self.get_circuit_holder()
|
||||||
.ok_or(ICError::NoCircuitHolder(self.id))?
|
.ok_or(ICError::NoCircuitHolder(self.id))?
|
||||||
|
.borrow_mut()
|
||||||
|
.as_mut_logicable()
|
||||||
|
.ok_or(ICError::CircuitHolderNotLogicable(self.id))?
|
||||||
.set_logic(LogicType::LineNumber, self.ip as f64, true)?;
|
.set_logic(LogicType::LineNumber, self.ip as f64, true)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,6 +223,7 @@ impl ObjectTemplate {
|
|||||||
readable_logic: Vec::new(),
|
readable_logic: Vec::new(),
|
||||||
writeable_logic: Vec::new(),
|
writeable_logic: Vec::new(),
|
||||||
occupant: None,
|
occupant: None,
|
||||||
|
quantity: info.quantity.unwrap_or(0),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
}),
|
}),
|
||||||
@@ -274,6 +275,7 @@ impl ObjectTemplate {
|
|||||||
})
|
})
|
||||||
.unwrap_or_else(|| Vec::new()),
|
.unwrap_or_else(|| Vec::new()),
|
||||||
occupant: None,
|
occupant: None,
|
||||||
|
quantity: info.quantity.unwrap_or(0),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
fields: s
|
fields: s
|
||||||
@@ -289,6 +291,7 @@ impl ObjectTemplate {
|
|||||||
value: s
|
value: s
|
||||||
.logic
|
.logic
|
||||||
.logic_values
|
.logic_values
|
||||||
|
.as_ref()
|
||||||
.map(|values| values.get(key))
|
.map(|values| values.get(key))
|
||||||
.flatten()
|
.flatten()
|
||||||
.copied()
|
.copied()
|
||||||
@@ -347,6 +350,7 @@ impl ObjectTemplate {
|
|||||||
})
|
})
|
||||||
.unwrap_or_else(|| Vec::new()),
|
.unwrap_or_else(|| Vec::new()),
|
||||||
occupant: None,
|
occupant: None,
|
||||||
|
quantity: info.quantity.unwrap_or(0),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
fields: s
|
fields: s
|
||||||
@@ -362,6 +366,7 @@ impl ObjectTemplate {
|
|||||||
value: s
|
value: s
|
||||||
.logic
|
.logic
|
||||||
.logic_values
|
.logic_values
|
||||||
|
.as_ref()
|
||||||
.map(|values| values.get(key))
|
.map(|values| values.get(key))
|
||||||
.flatten()
|
.flatten()
|
||||||
.copied()
|
.copied()
|
||||||
@@ -382,6 +387,7 @@ impl ObjectTemplate {
|
|||||||
pins: s
|
pins: s
|
||||||
.device
|
.device
|
||||||
.device_pins
|
.device_pins
|
||||||
|
.as_ref()
|
||||||
.map(|pins| Some(pins.clone()))
|
.map(|pins| Some(pins.clone()))
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
s.device
|
s.device
|
||||||
@@ -389,6 +395,7 @@ impl ObjectTemplate {
|
|||||||
.map(|pins_len| vec![None; pins_len])
|
.map(|pins_len| vec![None; pins_len])
|
||||||
}),
|
}),
|
||||||
device_info: s.device.clone(),
|
device_info: s.device.clone(),
|
||||||
|
reagents: s.device.reagents.clone(),
|
||||||
}),
|
}),
|
||||||
StructureLogicDeviceMemory(s)
|
StructureLogicDeviceMemory(s)
|
||||||
if matches!(s.memory.memory_access, MemoryAccess::Read) =>
|
if matches!(s.memory.memory_access, MemoryAccess::Read) =>
|
||||||
@@ -445,6 +452,7 @@ impl ObjectTemplate {
|
|||||||
})
|
})
|
||||||
.unwrap_or_else(|| Vec::new()),
|
.unwrap_or_else(|| Vec::new()),
|
||||||
occupant: None,
|
occupant: None,
|
||||||
|
quantity: info.quantity.unwrap_or(0),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
fields: s
|
fields: s
|
||||||
@@ -460,6 +468,7 @@ impl ObjectTemplate {
|
|||||||
value: s
|
value: s
|
||||||
.logic
|
.logic
|
||||||
.logic_values
|
.logic_values
|
||||||
|
.as_ref()
|
||||||
.map(|values| values.get(key))
|
.map(|values| values.get(key))
|
||||||
.flatten()
|
.flatten()
|
||||||
.copied()
|
.copied()
|
||||||
@@ -480,6 +489,7 @@ impl ObjectTemplate {
|
|||||||
pins: s
|
pins: s
|
||||||
.device
|
.device
|
||||||
.device_pins
|
.device_pins
|
||||||
|
.as_ref()
|
||||||
.map(|pins| Some(pins.clone()))
|
.map(|pins| Some(pins.clone()))
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
s.device
|
s.device
|
||||||
@@ -487,6 +497,7 @@ impl ObjectTemplate {
|
|||||||
.map(|pins_len| vec![None; pins_len])
|
.map(|pins_len| vec![None; pins_len])
|
||||||
}),
|
}),
|
||||||
device_info: s.device.clone(),
|
device_info: s.device.clone(),
|
||||||
|
reagents: s.device.reagents.clone(),
|
||||||
memory: s
|
memory: s
|
||||||
.memory
|
.memory
|
||||||
.values
|
.values
|
||||||
@@ -547,6 +558,7 @@ impl ObjectTemplate {
|
|||||||
})
|
})
|
||||||
.unwrap_or_else(|| Vec::new()),
|
.unwrap_or_else(|| Vec::new()),
|
||||||
occupant: None,
|
occupant: None,
|
||||||
|
quantity: info.quantity.unwrap_or(0),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
fields: s
|
fields: s
|
||||||
@@ -562,6 +574,7 @@ impl ObjectTemplate {
|
|||||||
value: s
|
value: s
|
||||||
.logic
|
.logic
|
||||||
.logic_values
|
.logic_values
|
||||||
|
.as_ref()
|
||||||
.map(|values| values.get(key))
|
.map(|values| values.get(key))
|
||||||
.flatten()
|
.flatten()
|
||||||
.copied()
|
.copied()
|
||||||
@@ -582,6 +595,7 @@ impl ObjectTemplate {
|
|||||||
pins: s
|
pins: s
|
||||||
.device
|
.device
|
||||||
.device_pins
|
.device_pins
|
||||||
|
.as_ref()
|
||||||
.map(|pins| Some(pins.clone()))
|
.map(|pins| Some(pins.clone()))
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
s.device
|
s.device
|
||||||
@@ -589,6 +603,7 @@ impl ObjectTemplate {
|
|||||||
.map(|pins_len| vec![None; pins_len])
|
.map(|pins_len| vec![None; pins_len])
|
||||||
}),
|
}),
|
||||||
device_info: s.device.clone(),
|
device_info: s.device.clone(),
|
||||||
|
reagents: s.device.reagents.clone(),
|
||||||
memory: s
|
memory: s
|
||||||
.memory
|
.memory
|
||||||
.values
|
.values
|
||||||
@@ -603,6 +618,7 @@ impl ObjectTemplate {
|
|||||||
vm,
|
vm,
|
||||||
item_info: i.item.clone(),
|
item_info: i.item.clone(),
|
||||||
parent_slot: None,
|
parent_slot: None,
|
||||||
|
damage: i.item.damage,
|
||||||
}),
|
}),
|
||||||
ItemSlots(i) => VMObject::new(GenericItemStorage {
|
ItemSlots(i) => VMObject::new(GenericItemStorage {
|
||||||
id,
|
id,
|
||||||
@@ -611,6 +627,7 @@ impl ObjectTemplate {
|
|||||||
vm,
|
vm,
|
||||||
item_info: i.item.clone(),
|
item_info: i.item.clone(),
|
||||||
parent_slot: None,
|
parent_slot: None,
|
||||||
|
damage: i.item.damage,
|
||||||
slots: i
|
slots: i
|
||||||
.slots
|
.slots
|
||||||
.iter()
|
.iter()
|
||||||
@@ -623,6 +640,7 @@ impl ObjectTemplate {
|
|||||||
readable_logic: Vec::new(),
|
readable_logic: Vec::new(),
|
||||||
writeable_logic: Vec::new(),
|
writeable_logic: Vec::new(),
|
||||||
occupant: None,
|
occupant: None,
|
||||||
|
quantity: info.quantity.unwrap_or(0),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
}),
|
}),
|
||||||
@@ -633,6 +651,7 @@ impl ObjectTemplate {
|
|||||||
vm,
|
vm,
|
||||||
item_info: i.item.clone(),
|
item_info: i.item.clone(),
|
||||||
parent_slot: None,
|
parent_slot: None,
|
||||||
|
damage: i.item.damage,
|
||||||
slots: i
|
slots: i
|
||||||
.slots
|
.slots
|
||||||
.iter()
|
.iter()
|
||||||
@@ -675,6 +694,7 @@ impl ObjectTemplate {
|
|||||||
})
|
})
|
||||||
.unwrap_or_else(|| Vec::new()),
|
.unwrap_or_else(|| Vec::new()),
|
||||||
occupant: None,
|
occupant: None,
|
||||||
|
quantity: info.quantity.unwrap_or(0),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
fields: i
|
fields: i
|
||||||
@@ -690,6 +710,7 @@ impl ObjectTemplate {
|
|||||||
value: i
|
value: i
|
||||||
.logic
|
.logic
|
||||||
.logic_values
|
.logic_values
|
||||||
|
.as_ref()
|
||||||
.map(|values| values.get(key))
|
.map(|values| values.get(key))
|
||||||
.flatten()
|
.flatten()
|
||||||
.copied()
|
.copied()
|
||||||
@@ -708,6 +729,7 @@ impl ObjectTemplate {
|
|||||||
vm,
|
vm,
|
||||||
item_info: i.item.clone(),
|
item_info: i.item.clone(),
|
||||||
parent_slot: None,
|
parent_slot: None,
|
||||||
|
damage: i.item.damage,
|
||||||
slots: i
|
slots: i
|
||||||
.slots
|
.slots
|
||||||
.iter()
|
.iter()
|
||||||
@@ -754,6 +776,7 @@ impl ObjectTemplate {
|
|||||||
})
|
})
|
||||||
.unwrap_or_else(|| Vec::new()),
|
.unwrap_or_else(|| Vec::new()),
|
||||||
occupant: None,
|
occupant: None,
|
||||||
|
quantity: info.quantity.unwrap_or(0),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
fields: i
|
fields: i
|
||||||
@@ -769,6 +792,7 @@ impl ObjectTemplate {
|
|||||||
value: i
|
value: i
|
||||||
.logic
|
.logic
|
||||||
.logic_values
|
.logic_values
|
||||||
|
.as_ref()
|
||||||
.map(|values| values.get(key))
|
.map(|values| values.get(key))
|
||||||
.flatten()
|
.flatten()
|
||||||
.copied()
|
.copied()
|
||||||
@@ -792,6 +816,7 @@ impl ObjectTemplate {
|
|||||||
vm,
|
vm,
|
||||||
item_info: i.item.clone(),
|
item_info: i.item.clone(),
|
||||||
parent_slot: None,
|
parent_slot: None,
|
||||||
|
damage: i.item.damage,
|
||||||
slots: i
|
slots: i
|
||||||
.slots
|
.slots
|
||||||
.iter()
|
.iter()
|
||||||
@@ -834,6 +859,7 @@ impl ObjectTemplate {
|
|||||||
})
|
})
|
||||||
.unwrap_or_else(|| Vec::new()),
|
.unwrap_or_else(|| Vec::new()),
|
||||||
occupant: None,
|
occupant: None,
|
||||||
|
quantity: info.quantity.unwrap_or(0),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
fields: i
|
fields: i
|
||||||
@@ -849,6 +875,7 @@ impl ObjectTemplate {
|
|||||||
value: i
|
value: i
|
||||||
.logic
|
.logic
|
||||||
.logic_values
|
.logic_values
|
||||||
|
.as_ref()
|
||||||
.map(|values| values.get(key))
|
.map(|values| values.get(key))
|
||||||
.flatten()
|
.flatten()
|
||||||
.copied()
|
.copied()
|
||||||
@@ -888,6 +915,11 @@ impl ObjectTemplate {
|
|||||||
wireless_transmit: None,
|
wireless_transmit: None,
|
||||||
wireless_receive: None,
|
wireless_receive: None,
|
||||||
network: None,
|
network: None,
|
||||||
|
plant: None,
|
||||||
|
suit: None,
|
||||||
|
chargeable: None,
|
||||||
|
reagent_interface: None,
|
||||||
|
fabricator: None,
|
||||||
} => {
|
} => {
|
||||||
// completely generic structure? not sure how this got created but it technically
|
// completely generic structure? not sure how this got created but it technically
|
||||||
// valid in the data model
|
// valid in the data model
|
||||||
@@ -914,6 +946,11 @@ impl ObjectTemplate {
|
|||||||
wireless_transmit: None,
|
wireless_transmit: None,
|
||||||
wireless_receive: None,
|
wireless_receive: None,
|
||||||
network: None,
|
network: None,
|
||||||
|
plant: None,
|
||||||
|
suit: None,
|
||||||
|
chargeable: None,
|
||||||
|
reagent_interface: None,
|
||||||
|
fabricator: None,
|
||||||
} => Ok(ObjectTemplate::StructureSlots(StructureSlotsTemplate {
|
} => Ok(ObjectTemplate::StructureSlots(StructureSlotsTemplate {
|
||||||
object: Some(obj.into()),
|
object: Some(obj.into()),
|
||||||
prefab: obj.into(),
|
prefab: obj.into(),
|
||||||
@@ -937,6 +974,11 @@ impl ObjectTemplate {
|
|||||||
wireless_transmit: _wt,
|
wireless_transmit: _wt,
|
||||||
wireless_receive: _wr,
|
wireless_receive: _wr,
|
||||||
network: None,
|
network: None,
|
||||||
|
plant: None,
|
||||||
|
suit: None,
|
||||||
|
chargeable: None,
|
||||||
|
reagent_interface: None,
|
||||||
|
fabricator: None,
|
||||||
} => Ok(ObjectTemplate::StructureLogic(StructureLogicTemplate {
|
} => Ok(ObjectTemplate::StructureLogic(StructureLogicTemplate {
|
||||||
object: Some(obj.into()),
|
object: Some(obj.into()),
|
||||||
prefab: obj.into(),
|
prefab: obj.into(),
|
||||||
@@ -961,6 +1003,11 @@ impl ObjectTemplate {
|
|||||||
wireless_transmit: _wt,
|
wireless_transmit: _wt,
|
||||||
wireless_receive: _wr,
|
wireless_receive: _wr,
|
||||||
network: None,
|
network: None,
|
||||||
|
plant: None,
|
||||||
|
suit: None,
|
||||||
|
chargeable: None,
|
||||||
|
reagent_interface: None,
|
||||||
|
fabricator: None,
|
||||||
} => Ok(ObjectTemplate::StructureLogicDevice(
|
} => Ok(ObjectTemplate::StructureLogicDevice(
|
||||||
StructureLogicDeviceTemplate {
|
StructureLogicDeviceTemplate {
|
||||||
object: Some(obj.into()),
|
object: Some(obj.into()),
|
||||||
@@ -988,6 +1035,11 @@ impl ObjectTemplate {
|
|||||||
wireless_transmit: _wt,
|
wireless_transmit: _wt,
|
||||||
wireless_receive: _wr,
|
wireless_receive: _wr,
|
||||||
network: None,
|
network: None,
|
||||||
|
plant: None,
|
||||||
|
suit: None,
|
||||||
|
chargeable: None,
|
||||||
|
reagent_interface: None,
|
||||||
|
fabricator: None,
|
||||||
} => Ok(ObjectTemplate::StructureLogicDeviceMemory(
|
} => Ok(ObjectTemplate::StructureLogicDeviceMemory(
|
||||||
StructureLogicDeviceMemoryTemplate {
|
StructureLogicDeviceMemoryTemplate {
|
||||||
object: Some(obj.into()),
|
object: Some(obj.into()),
|
||||||
@@ -1018,6 +1070,11 @@ impl ObjectTemplate {
|
|||||||
wireless_transmit: None,
|
wireless_transmit: None,
|
||||||
wireless_receive: None,
|
wireless_receive: None,
|
||||||
network: None,
|
network: None,
|
||||||
|
plant: None,
|
||||||
|
suit: None,
|
||||||
|
chargeable: None,
|
||||||
|
reagent_interface: None,
|
||||||
|
fabricator: None,
|
||||||
} => Ok(ObjectTemplate::Item(ItemTemplate {
|
} => Ok(ObjectTemplate::Item(ItemTemplate {
|
||||||
object: Some(obj.into()),
|
object: Some(obj.into()),
|
||||||
prefab: obj.into(),
|
prefab: obj.into(),
|
||||||
@@ -1040,6 +1097,11 @@ impl ObjectTemplate {
|
|||||||
wireless_transmit: None,
|
wireless_transmit: None,
|
||||||
wireless_receive: None,
|
wireless_receive: None,
|
||||||
network: None,
|
network: None,
|
||||||
|
plant: None,
|
||||||
|
suit: None,
|
||||||
|
chargeable: None,
|
||||||
|
reagent_interface: None,
|
||||||
|
fabricator: None,
|
||||||
} => Ok(ObjectTemplate::ItemSlots(ItemSlotsTemplate {
|
} => Ok(ObjectTemplate::ItemSlots(ItemSlotsTemplate {
|
||||||
object: Some(obj.into()),
|
object: Some(obj.into()),
|
||||||
prefab: obj.into(),
|
prefab: obj.into(),
|
||||||
@@ -1063,6 +1125,11 @@ impl ObjectTemplate {
|
|||||||
wireless_transmit: _wt,
|
wireless_transmit: _wt,
|
||||||
wireless_receive: _wr,
|
wireless_receive: _wr,
|
||||||
network: None,
|
network: None,
|
||||||
|
plant: None,
|
||||||
|
suit: None,
|
||||||
|
chargeable: None,
|
||||||
|
reagent_interface: None,
|
||||||
|
fabricator: None,
|
||||||
} => Ok(ObjectTemplate::ItemLogic(ItemLogicTemplate {
|
} => Ok(ObjectTemplate::ItemLogic(ItemLogicTemplate {
|
||||||
object: Some(obj.into()),
|
object: Some(obj.into()),
|
||||||
prefab: obj.into(),
|
prefab: obj.into(),
|
||||||
@@ -1087,6 +1154,11 @@ impl ObjectTemplate {
|
|||||||
wireless_transmit: _wt,
|
wireless_transmit: _wt,
|
||||||
wireless_receive: _wr,
|
wireless_receive: _wr,
|
||||||
network: None,
|
network: None,
|
||||||
|
plant: None,
|
||||||
|
suit: None,
|
||||||
|
chargeable: None,
|
||||||
|
reagent_interface: None,
|
||||||
|
fabricator: None,
|
||||||
} => Ok(ObjectTemplate::ItemLogicMemory(ItemLogicMemoryTemplate {
|
} => Ok(ObjectTemplate::ItemLogicMemory(ItemLogicMemoryTemplate {
|
||||||
object: Some(obj.into()),
|
object: Some(obj.into()),
|
||||||
prefab: obj.into(),
|
prefab: obj.into(),
|
||||||
@@ -1117,6 +1189,11 @@ fn freeze_storage(storage: StorageRef<'_>, vm: &Rc<VM>) -> Result<Vec<SlotInfo>,
|
|||||||
ObjectTemplate::freeze_object(&occupant, vm)
|
ObjectTemplate::freeze_object(&occupant, vm)
|
||||||
})
|
})
|
||||||
.map_or(Ok(None), |v| v.map(Some))?,
|
.map_or(Ok(None), |v| v.map(Some))?,
|
||||||
|
quantity: if slot.quantity == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(slot.quantity)
|
||||||
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
@@ -1134,7 +1211,8 @@ pub struct PrefabInfo {
|
|||||||
|
|
||||||
impl From<&VMObject> for PrefabInfo {
|
impl From<&VMObject> for PrefabInfo {
|
||||||
fn from(obj: &VMObject) -> Self {
|
fn from(obj: &VMObject) -> Self {
|
||||||
let obj_prefab = obj.borrow().get_prefab();
|
let obj_ref = obj.borrow();
|
||||||
|
let obj_prefab = obj_ref.get_prefab();
|
||||||
let prefab_lookup = StationpediaPrefab::from_repr(obj_prefab.hash);
|
let prefab_lookup = StationpediaPrefab::from_repr(obj_prefab.hash);
|
||||||
PrefabInfo {
|
PrefabInfo {
|
||||||
prefab_name: obj_prefab.value.clone(),
|
prefab_name: obj_prefab.value.clone(),
|
||||||
@@ -1177,6 +1255,8 @@ pub struct SlotInfo {
|
|||||||
pub typ: SlotClass,
|
pub typ: SlotClass,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub occupant: Option<ObjectTemplate>,
|
pub occupant: Option<ObjectTemplate>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub quantity: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||||
@@ -1291,6 +1371,8 @@ pub struct ItemInfo {
|
|||||||
pub reagents: Option<BTreeMap<String, f64>>,
|
pub reagents: Option<BTreeMap<String, f64>>,
|
||||||
pub slot_class: SlotClass,
|
pub slot_class: SlotClass,
|
||||||
pub sorting_class: SortingClass,
|
pub sorting_class: SortingClass,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub damage: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ItemRef<'_>> for ItemInfo {
|
impl From<ItemRef<'_>> for ItemInfo {
|
||||||
@@ -1303,6 +1385,11 @@ impl From<ItemRef<'_>> for ItemInfo {
|
|||||||
reagents: item.reagents().cloned(),
|
reagents: item.reagents().cloned(),
|
||||||
slot_class: item.slot_class(),
|
slot_class: item.slot_class(),
|
||||||
sorting_class: item.sorting_class(),
|
sorting_class: item.sorting_class(),
|
||||||
|
damage: if item.get_damage() == 0.0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(item.get_damage())
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1316,7 +1403,7 @@ pub struct ConnectionInfo {
|
|||||||
pub network: Option<ObjectID>,
|
pub network: Option<ObjectID>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct DeviceInfo {
|
pub struct DeviceInfo {
|
||||||
pub connection_list: Vec<ConnectionInfo>,
|
pub connection_list: Vec<ConnectionInfo>,
|
||||||
@@ -1332,10 +1419,13 @@ pub struct DeviceInfo {
|
|||||||
pub has_on_off_state: bool,
|
pub has_on_off_state: bool,
|
||||||
pub has_open_state: bool,
|
pub has_open_state: bool,
|
||||||
pub has_reagents: bool,
|
pub has_reagents: bool,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub reagents: Option<BTreeMap<i32, f64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DeviceRef<'_>> for DeviceInfo {
|
impl From<DeviceRef<'_>> for DeviceInfo {
|
||||||
fn from(device: DeviceRef) -> Self {
|
fn from(device: DeviceRef) -> Self {
|
||||||
|
let reagents: BTreeMap<i32, f64> = device.get_reagents().iter().copied().collect();
|
||||||
DeviceInfo {
|
DeviceInfo {
|
||||||
connection_list: device
|
connection_list: device
|
||||||
.connection_list()
|
.connection_list()
|
||||||
@@ -1354,6 +1444,11 @@ impl From<DeviceRef<'_>> for DeviceInfo {
|
|||||||
has_color_state: device.has_color_state(),
|
has_color_state: device.has_color_state(),
|
||||||
has_atmosphere: device.has_atmosphere(),
|
has_atmosphere: device.has_atmosphere(),
|
||||||
has_activate_state: device.has_activate_state(),
|
has_activate_state: device.has_activate_state(),
|
||||||
|
reagents: if reagents.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(reagents)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
instructions::{traits::ICInstructable, Instruction},
|
instructions::{traits::ICInstructable, Instruction},
|
||||||
object::{
|
object::{
|
||||||
errors::{LogicError, MemoryError},
|
errors::{LogicError, MemoryError}, macros::tag_object_traits, ObjectID, Slot, VMObject
|
||||||
macros::tag_object_traits,
|
|
||||||
ObjectID, Slot,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -82,27 +80,15 @@ tag_object_traits! {
|
|||||||
&self,
|
&self,
|
||||||
device: i32,
|
device: i32,
|
||||||
connection: Option<usize>,
|
connection: Option<usize>,
|
||||||
) -> Option<LogicableRef>;
|
) -> Option<VMObject>;
|
||||||
/// i32::MAX is db
|
/// i32::MAX is db
|
||||||
fn get_logicable_from_index_mut(
|
|
||||||
&self,
|
|
||||||
device: i32,
|
|
||||||
connection: Option<usize>,
|
|
||||||
) -> Option<LogicableRefMut>;
|
|
||||||
fn get_logicable_from_id(
|
fn get_logicable_from_id(
|
||||||
&self,
|
&self,
|
||||||
device: ObjectID,
|
device: ObjectID,
|
||||||
connection: Option<usize>,
|
connection: Option<usize>,
|
||||||
) -> Option<LogicableRef>;
|
) -> Option<VMObject>;
|
||||||
fn get_logicable_from_id_mut(
|
|
||||||
&self,
|
|
||||||
device: ObjectID,
|
|
||||||
connection: Option<usize>,
|
|
||||||
) -> Option<LogicableRefMut>;
|
|
||||||
fn get_source_code(&self) -> String;
|
fn get_source_code(&self) -> String;
|
||||||
fn set_source_code(&self, code: String);
|
fn set_source_code(&self, code: String);
|
||||||
fn get_batch(&self) -> Vec<LogicableRef>;
|
|
||||||
fn get_batch_mut(&self) -> Vec<LogicableRefMut>;
|
|
||||||
fn get_ic(&self) -> Option<ObjectID>;
|
fn get_ic(&self) -> Option<ObjectID>;
|
||||||
fn hault_and_catch_fire(&mut self);
|
fn hault_and_catch_fire(&mut self);
|
||||||
}
|
}
|
||||||
@@ -117,10 +103,25 @@ tag_object_traits! {
|
|||||||
fn sorting_class(&self) -> SortingClass;
|
fn sorting_class(&self) -> SortingClass;
|
||||||
fn get_parent_slot(&self) -> Option<ParentSlotInfo>;
|
fn get_parent_slot(&self) -> Option<ParentSlotInfo>;
|
||||||
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>);
|
fn set_parent_slot(&mut self, info: Option<ParentSlotInfo>);
|
||||||
|
fn get_damage(&self) -> f32;
|
||||||
|
fn set_damage(&mut self, damage: f32);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Plant {
|
||||||
|
fn get_efficiency(&self) -> f64;
|
||||||
|
fn get_health(&self) -> f64;
|
||||||
|
fn get_growth(&self) -> f64;
|
||||||
|
fn is_mature(&self) -> bool;
|
||||||
|
fn is_seeding(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Suit {
|
||||||
|
fn pressure_waste(&self) -> f64;
|
||||||
|
fn pressure_air(&self) -> f64;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IntegratedCircuit: Logicable + MemoryWritable + SourceCode + Item {
|
pub trait IntegratedCircuit: Logicable + MemoryWritable + SourceCode + Item {
|
||||||
fn get_circuit_holder(&self) -> Option<CircuitHolderRef>;
|
fn get_circuit_holder(&self) -> Option<VMObject>;
|
||||||
fn get_instruction_pointer(&self) -> f64;
|
fn get_instruction_pointer(&self) -> f64;
|
||||||
fn set_next_instruction(&mut self, next_instruction: f64);
|
fn set_next_instruction(&mut self, next_instruction: f64);
|
||||||
fn set_next_instruction_relative(&mut self, offset: f64) {
|
fn set_next_instruction_relative(&mut self, offset: f64) {
|
||||||
@@ -138,7 +139,7 @@ tag_object_traits! {
|
|||||||
fn pop_stack(&mut self) -> Result<f64, ICError>;
|
fn pop_stack(&mut self) -> Result<f64, ICError>;
|
||||||
fn peek_stack(&self) -> Result<f64, ICError>;
|
fn peek_stack(&self) -> Result<f64, ICError>;
|
||||||
fn get_stack(&self, addr: f64) -> Result<f64, ICError>;
|
fn get_stack(&self, addr: f64) -> Result<f64, ICError>;
|
||||||
fn put_stack(&self, addr: f64, val: f64) -> Result<f64, ICError>;
|
fn put_stack(&mut self, addr: f64, val: f64) -> Result<f64, ICError>;
|
||||||
fn get_aliases(&self) -> &BTreeMap<String, crate::vm::instructions::operands::Operand>;
|
fn get_aliases(&self) -> &BTreeMap<String, crate::vm::instructions::operands::Operand>;
|
||||||
fn get_aliases_mut(&mut self) -> &mut BTreeMap<String, crate::vm::instructions::operands::Operand>;
|
fn get_aliases_mut(&mut self) -> &mut BTreeMap<String, crate::vm::instructions::operands::Operand>;
|
||||||
fn get_defines(&self) -> &BTreeMap<String, f64>;
|
fn get_defines(&self) -> &BTreeMap<String, f64>;
|
||||||
@@ -152,6 +153,21 @@ tag_object_traits! {
|
|||||||
fn step(&mut self, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError>;
|
fn step(&mut self, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Chargeable {
|
||||||
|
fn get_charge(&self) -> f32;
|
||||||
|
fn set_charge(&mut self, charge: f32);
|
||||||
|
fn get_max_charge(&self) -> f32;
|
||||||
|
fn get_charge_ratio(&self) -> f32 {
|
||||||
|
self.get_charge() / self.get_max_charge()
|
||||||
|
}
|
||||||
|
fn get_charge_delta(&self) -> f32 {
|
||||||
|
self.get_charge() - self.get_max_charge()
|
||||||
|
}
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.get_charge() == 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Instructable: MemoryWritable {
|
pub trait Instructable: MemoryWritable {
|
||||||
// fn get_instructions(&self) -> Vec<LogicInstruction>
|
// fn get_instructions(&self) -> Vec<LogicInstruction>
|
||||||
}
|
}
|
||||||
@@ -172,7 +188,7 @@ tag_object_traits! {
|
|||||||
fn connection_list(&self) -> &[Connection];
|
fn connection_list(&self) -> &[Connection];
|
||||||
fn connection_list_mut(&mut self) -> &mut [Connection];
|
fn connection_list_mut(&mut self) -> &mut [Connection];
|
||||||
fn device_pins(&self) -> Option<&[Option<ObjectID>]>;
|
fn device_pins(&self) -> Option<&[Option<ObjectID>]>;
|
||||||
fn device_pins_mut(&self) -> Option<&mut [Option<ObjectID>]>;
|
fn device_pins_mut(&mut self) -> Option<&mut [Option<ObjectID>]>;
|
||||||
fn has_activate_state(&self) -> bool;
|
fn has_activate_state(&self) -> bool;
|
||||||
fn has_atmosphere(&self) -> bool;
|
fn has_atmosphere(&self) -> bool;
|
||||||
fn has_color_state(&self) -> bool;
|
fn has_color_state(&self) -> bool;
|
||||||
|
|||||||
Reference in New Issue
Block a user