refactor(vm): cleanup borrow usage, impl slot logic

This commit is contained in:
Rachel Powers
2024-05-15 22:32:46 -07:00
parent e928813c0e
commit cc6cc355dc
14 changed files with 687 additions and 1118 deletions

View File

@@ -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(),
}
}
}

View File

@@ -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} ")]

View File

@@ -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(())
} }

View File

@@ -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;

View File

@@ -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))
} }

View File

@@ -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() {

View File

@@ -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(),
} }
} }
} }

View File

@@ -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,
} }

View File

@@ -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
}
} }
}; };
} }

View File

@@ -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>>,

View File

@@ -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 {}

View File

@@ -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(())
} }

View File

@@ -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)
},
} }
} }
} }

View File

@@ -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;