move mutability within IC struct to limit borrow panics
This commit is contained in:
@@ -628,14 +628,14 @@ impl Device {
|
||||
LogicType::LineNumber,
|
||||
LogicField {
|
||||
field_type: FieldType::ReadWrite,
|
||||
value: ic.ip as f64,
|
||||
value: ic.ip() as f64,
|
||||
},
|
||||
);
|
||||
copy.insert(
|
||||
LogicType::Error,
|
||||
LogicField {
|
||||
field_type: FieldType::Read,
|
||||
value: match ic.state {
|
||||
value: match *ic.state.borrow() {
|
||||
ICState::Error(_) => 1.0,
|
||||
_ => 0.0,
|
||||
},
|
||||
@@ -736,19 +736,12 @@ impl Device {
|
||||
|
||||
pub fn get_field(&self, typ: LogicType, vm: &VM) -> Result<f64, ICError> {
|
||||
if typ == LogicType::LineNumber && self.ic.is_some() {
|
||||
if let Ok(ic) = vm
|
||||
let ic = vm
|
||||
.ics
|
||||
.get(&self.ic.unwrap())
|
||||
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
|
||||
.try_borrow()
|
||||
{
|
||||
Ok(ic.ip as f64)
|
||||
} else {
|
||||
// HACK: the game succeeds in getting the correct line number
|
||||
// when reading it's own IC, but we'll panic trying to do it here
|
||||
// this is worked around in internal_step so just return 0 here
|
||||
Ok(0.0)
|
||||
}
|
||||
.borrow();
|
||||
Ok(ic.ip() as f64)
|
||||
} else if let Some(field) = self.get_fields(vm).get(&typ) {
|
||||
if field.field_type == FieldType::Read || field.field_type == FieldType::ReadWrite {
|
||||
Ok(field.value)
|
||||
@@ -773,16 +766,12 @@ impl Device {
|
||||
{
|
||||
Err(ICError::ReadOnlyField(typ.to_string()))
|
||||
} else if typ == LogicType::LineNumber && self.ic.is_some() {
|
||||
// try borrow to set ip, we should only fail if the ic is in use aka is is *our* ic
|
||||
// in game trying to set your own ic's LineNumber appears to be a Nop so this is fine.
|
||||
if let Ok(mut ic) = vm
|
||||
let ic = vm
|
||||
.ics
|
||||
.get(&self.ic.unwrap())
|
||||
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
|
||||
.try_borrow_mut()
|
||||
{
|
||||
ic.ip = val as u32;
|
||||
}
|
||||
.borrow();
|
||||
ic.set_ip(val as u32);
|
||||
Ok(())
|
||||
} else if let Some(field) = self.fields.get_mut(&typ) {
|
||||
if field.field_type == FieldType::Write
|
||||
@@ -818,20 +807,12 @@ impl Device {
|
||||
&& self.ic.is_some()
|
||||
&& typ == SlotLogicType::LineNumber
|
||||
{
|
||||
// try borrow to get ip, we should only fail if the ic is in us aka is is *our* ic
|
||||
if let Ok(ic) = vm
|
||||
let ic = vm
|
||||
.ics
|
||||
.get(&self.ic.unwrap())
|
||||
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
|
||||
.try_borrow()
|
||||
{
|
||||
Ok(ic.ip as f64)
|
||||
} else {
|
||||
// HACK: the game succeeds in getting the correct line number
|
||||
// when reading it's own IC, but we'll panic trying to do it here
|
||||
// this is worked around in internal_step so just return 0 here
|
||||
Ok(0.0)
|
||||
}
|
||||
.borrow();
|
||||
Ok(ic.ip() as f64)
|
||||
} else {
|
||||
Ok(slot.get_field(typ))
|
||||
}
|
||||
@@ -848,32 +829,18 @@ impl Device {
|
||||
.ok_or(ICError::SlotIndexOutOfRange(index))?;
|
||||
let mut fields = slot.get_fields();
|
||||
if slot.typ == SlotType::ProgrammableChip && slot.occupant.is_some() && self.ic.is_some() {
|
||||
// try borrow to get ip, we should only fail if the ic is in us aka is is *our* ic
|
||||
if let Ok(ic) = vm
|
||||
let ic = vm
|
||||
.ics
|
||||
.get(&self.ic.unwrap())
|
||||
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
|
||||
.try_borrow()
|
||||
{
|
||||
fields.insert(
|
||||
SlotLogicType::LineNumber,
|
||||
LogicField {
|
||||
field_type: FieldType::ReadWrite,
|
||||
value: ic.ip as f64,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
// HACK: the game succeeds in getting the correct line number
|
||||
// when reading it's own IC, but we'll panic trying to do it here
|
||||
// this is worked around in internal_step so just return 0 here
|
||||
fields.insert(
|
||||
SlotLogicType::LineNumber,
|
||||
LogicField {
|
||||
field_type: FieldType::ReadWrite,
|
||||
value: 0.0,
|
||||
},
|
||||
);
|
||||
}
|
||||
.borrow();
|
||||
fields.insert(
|
||||
SlotLogicType::LineNumber,
|
||||
LogicField {
|
||||
field_type: FieldType::ReadWrite,
|
||||
value: ic.ip() as f64,
|
||||
},
|
||||
);
|
||||
}
|
||||
Ok(fields)
|
||||
}
|
||||
@@ -883,32 +850,14 @@ impl Device {
|
||||
index: f64,
|
||||
typ: SlotLogicType,
|
||||
val: f64,
|
||||
vm: &VM,
|
||||
_vm: &VM,
|
||||
force: bool,
|
||||
) -> Result<(), ICError> {
|
||||
let slot = self
|
||||
.slots
|
||||
.get_mut(index as usize)
|
||||
.ok_or(ICError::SlotIndexOutOfRange(index))?;
|
||||
if slot.typ == SlotType::ProgrammableChip
|
||||
&& slot.occupant.is_some()
|
||||
&& self.ic.is_some()
|
||||
&& typ == SlotLogicType::LineNumber
|
||||
{
|
||||
// try borrow to set ip, we shoudl only fail if the ic is in us aka is is *our* ic
|
||||
// in game trying to set your own ic's LineNumber appears to be a Nop so this is fine.
|
||||
if let Ok(mut ic) = vm
|
||||
.ics
|
||||
.get(&self.ic.unwrap())
|
||||
.ok_or_else(|| ICError::UnknownDeviceID(self.ic.unwrap() as f64))?
|
||||
.try_borrow_mut()
|
||||
{
|
||||
ic.ip = val as u32;
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
slot.set_field(typ, val, force)
|
||||
}
|
||||
slot.set_field(typ, val, force)
|
||||
}
|
||||
|
||||
pub fn get_slot(&self, index: f64) -> Result<&Slot, ICError> {
|
||||
|
||||
@@ -431,6 +431,7 @@ impl Operand {
|
||||
Device::Numbered(p) => {
|
||||
let dp = ic
|
||||
.pins
|
||||
.borrow()
|
||||
.get(p as usize)
|
||||
.ok_or(interpreter::ICError::DeviceIndexOutOfRange(p as f64))
|
||||
.copied()?;
|
||||
@@ -443,6 +444,7 @@ impl Operand {
|
||||
let val = ic.get_register(indirection, target)?;
|
||||
let dp = ic
|
||||
.pins
|
||||
.borrow()
|
||||
.get(val as usize)
|
||||
.ok_or(interpreter::ICError::DeviceIndexOutOfRange(val))
|
||||
.copied()?;
|
||||
@@ -522,11 +524,11 @@ impl Operand {
|
||||
pub fn translate_alias(&self, ic: &interpreter::IC) -> Self {
|
||||
match &self {
|
||||
Operand::Identifier(id) => {
|
||||
if let Some(alias) = ic.aliases.get(&id.name) {
|
||||
if let Some(alias) = ic.aliases.borrow().get(&id.name) {
|
||||
alias.clone()
|
||||
} else if let Some(define) = ic.defines.get(&id.name) {
|
||||
} else if let Some(define) = ic.defines.borrow().get(&id.name) {
|
||||
Operand::Number(Number::Float(*define))
|
||||
} else if let Some(label) = ic.program.labels.get(&id.name) {
|
||||
} else if let Some(label) = ic.program.borrow().labels.get(&id.name) {
|
||||
Operand::Number(Number::Float(*label as f64))
|
||||
} else {
|
||||
self.clone()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use core::f64;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{ops::Deref, string::ToString};
|
||||
use std::{cell::{Cell, RefCell}, ops::Deref, string::ToString};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
error::Error,
|
||||
@@ -180,21 +180,20 @@ impl Display for ICState {
|
||||
pub struct IC {
|
||||
pub device: u32,
|
||||
pub id: u32,
|
||||
pub registers: [f64; 18],
|
||||
pub registers: RefCell<[f64; 18]>,
|
||||
/// Instruction Pointer
|
||||
pub ip: u32,
|
||||
pub ip: Cell<u32>,
|
||||
/// Instruction Count since last yield
|
||||
pub ic: u16,
|
||||
pub stack: [f64; 512],
|
||||
pub aliases: HashMap<String, grammar::Operand>,
|
||||
pub defines: HashMap<String, f64>,
|
||||
pub pins: [Option<u32>; 6],
|
||||
pub code: String,
|
||||
pub program: Program,
|
||||
pub state: ICState,
|
||||
pub ic: Cell<u16>,
|
||||
pub stack: RefCell<[f64; 512]>,
|
||||
pub aliases: RefCell<HashMap<String, grammar::Operand>>,
|
||||
pub defines: RefCell<HashMap<String, f64>>,
|
||||
pub pins: RefCell<[Option<u32>; 6]>,
|
||||
pub code: RefCell<String>,
|
||||
pub program: RefCell<Program>,
|
||||
pub state: RefCell<ICState>,
|
||||
}
|
||||
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FrozenIC {
|
||||
@@ -215,21 +214,22 @@ pub struct FrozenIC {
|
||||
}
|
||||
|
||||
impl<T> From<T> for FrozenIC
|
||||
where T: Deref<Target = IC>
|
||||
where
|
||||
T: Deref<Target = IC>,
|
||||
{
|
||||
fn from(ic: T) -> Self {
|
||||
FrozenIC {
|
||||
device: ic.device,
|
||||
id: ic.id,
|
||||
registers: ic.registers,
|
||||
ip: ic.ip,
|
||||
ic: ic.ic,
|
||||
stack: ic.stack,
|
||||
aliases: ic.aliases.clone(),
|
||||
defines: ic.defines.clone(),
|
||||
pins: ic.pins,
|
||||
state: ic.state.clone(),
|
||||
code: ic.code.clone(),
|
||||
registers: *ic.registers.borrow(),
|
||||
ip: ic.ip.get(),
|
||||
ic: ic.ic.get(),
|
||||
stack: *ic.stack.borrow(),
|
||||
aliases: ic.aliases.borrow().clone(),
|
||||
defines: ic.defines.borrow().clone(),
|
||||
pins: *ic.pins.borrow(),
|
||||
state: ic.state.borrow().clone(),
|
||||
code: ic.code.borrow().clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,16 +239,16 @@ impl From<FrozenIC> for IC {
|
||||
IC {
|
||||
device: value.device,
|
||||
id: value.id,
|
||||
registers: value.registers,
|
||||
ip: value.ip,
|
||||
ic: value.ic,
|
||||
stack: value.stack,
|
||||
aliases: value.aliases,
|
||||
defines: value.defines,
|
||||
pins: value.pins,
|
||||
state: value.state,
|
||||
code: value.code.clone(),
|
||||
program: Program::from_code_with_invalid(&value.code),
|
||||
registers: RefCell::new(value.registers),
|
||||
ip: Cell::new(value.ip),
|
||||
ic: Cell::new(value.ic),
|
||||
stack: RefCell::new(value.stack),
|
||||
aliases: RefCell::new(value.aliases),
|
||||
defines: RefCell::new(value.defines),
|
||||
pins: RefCell::new(value.pins),
|
||||
state: RefCell::new(value.state),
|
||||
code: RefCell::new(value.code.clone()),
|
||||
program: RefCell::new(Program::from_code_with_invalid(&value.code)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -369,57 +369,49 @@ impl IC {
|
||||
IC {
|
||||
device,
|
||||
id,
|
||||
ip: 0,
|
||||
ic: 0,
|
||||
registers: [0.0; 18],
|
||||
stack: [0.0; 512],
|
||||
pins: [None; 6],
|
||||
program: Program::new(),
|
||||
code: String::new(),
|
||||
aliases: HashMap::new(),
|
||||
defines: HashMap::new(),
|
||||
state: ICState::Start,
|
||||
ip: Cell::new(0),
|
||||
ic: Cell::new(0),
|
||||
registers: RefCell::new([0.0; 18]),
|
||||
stack: RefCell::new([0.0; 512]),
|
||||
pins: RefCell::new([None; 6]),
|
||||
program: RefCell::new(Program::new()),
|
||||
code: RefCell::new(String::new()),
|
||||
aliases: RefCell::new(HashMap::new()),
|
||||
defines: RefCell::new(HashMap::new()),
|
||||
state: RefCell::new(ICState::Start),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.ip = 0;
|
||||
self.ic = 0;
|
||||
self.registers = [0.0; 18];
|
||||
self.stack = [0.0; 512];
|
||||
self.aliases = HashMap::new();
|
||||
self.defines = HashMap::new();
|
||||
self.state = ICState::Start;
|
||||
pub fn reset(&self) {
|
||||
self.ip.replace(0);
|
||||
self.ic.replace(0);
|
||||
self.registers.replace([0.0; 18]);
|
||||
self.stack.replace([0.0; 512]);
|
||||
self.aliases.replace(HashMap::new());
|
||||
self.defines.replace(HashMap::new());
|
||||
self.state.replace(ICState::Start);
|
||||
}
|
||||
|
||||
/// Set program code if it's valid
|
||||
pub fn set_code(&mut self, code: &str) -> Result<(), ICError> {
|
||||
pub fn set_code(&self, code: &str) -> Result<(), ICError> {
|
||||
let prog = Program::try_from_code(code)?;
|
||||
self.ip = 0;
|
||||
self.ic = 0;
|
||||
self.aliases = HashMap::new();
|
||||
self.defines = HashMap::new();
|
||||
self.program = prog;
|
||||
self.code = code.to_string();
|
||||
self.program.replace(prog);
|
||||
self.code.replace(code.to_string());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set program code and translate invalid lines to Nop, collecting errors
|
||||
pub fn set_code_invalid(&mut self, code: &str) {
|
||||
let prog = Program::from_code_with_invalid(code);
|
||||
self.ip = 0;
|
||||
self.ic = 0;
|
||||
self.aliases = HashMap::new();
|
||||
self.defines = HashMap::new();
|
||||
self.program = prog;
|
||||
self.code = code.to_string();
|
||||
self.program.replace(prog);
|
||||
self.code.replace(code.to_string());
|
||||
}
|
||||
|
||||
pub fn get_real_target(&self, indirection: u32, target: u32) -> Result<f64, ICError> {
|
||||
let mut i = indirection;
|
||||
let mut t = target as f64;
|
||||
while i > 0 {
|
||||
if let Some(new_t) = self.registers.get(t as usize) {
|
||||
if let Some(new_t) = self.registers.borrow().get(t as usize) {
|
||||
t = *new_t;
|
||||
} else {
|
||||
return Err(ICError::RegisterIndexOutOfRange(t));
|
||||
@@ -432,6 +424,7 @@ impl IC {
|
||||
pub fn get_register(&self, indirection: u32, target: u32) -> Result<f64, ICError> {
|
||||
let t = self.get_real_target(indirection, target)?;
|
||||
self.registers
|
||||
.borrow()
|
||||
.get(t as usize)
|
||||
.ok_or(ICError::RegisterIndexOutOfRange(t))
|
||||
.copied()
|
||||
@@ -439,72 +432,76 @@ impl IC {
|
||||
|
||||
/// sets a register thorough, recursing through provided indirection, returns value previously
|
||||
pub fn set_register(
|
||||
&mut self,
|
||||
&self,
|
||||
indirection: u32,
|
||||
target: u32,
|
||||
val: f64,
|
||||
) -> Result<f64, ICError> {
|
||||
let t = self.get_real_target(indirection, target)?;
|
||||
let old_val = self
|
||||
.registers
|
||||
let mut registers = self.registers.borrow_mut();
|
||||
let old_val = registers
|
||||
.get(t as usize)
|
||||
.ok_or(ICError::RegisterIndexOutOfRange(t))
|
||||
.copied()?;
|
||||
self.registers[t as usize] = val;
|
||||
registers[t as usize] = val;
|
||||
Ok(old_val)
|
||||
}
|
||||
|
||||
/// save ip to 'ra' or register 18
|
||||
fn al(&mut self) {
|
||||
self.registers[17] = self.ip as f64 + 1.0;
|
||||
fn al(&self) {
|
||||
self.registers.borrow_mut()[17] = self.ip() as f64 + 1.0;
|
||||
}
|
||||
|
||||
pub fn push(&mut self, val: f64) -> Result<f64, ICError> {
|
||||
let sp = (self.registers[16].round()) as i32;
|
||||
pub fn push(&self, val: f64) -> Result<f64, ICError> {
|
||||
let mut registers = self.registers.borrow_mut();
|
||||
let mut stack = self.stack.borrow_mut();
|
||||
let sp = (registers[16].round()) as i32;
|
||||
if sp < 0 {
|
||||
Err(ICError::StackUnderflow)
|
||||
} else if sp >= 512 {
|
||||
Err(ICError::StackOverflow)
|
||||
} else {
|
||||
let last = self.stack[sp as usize];
|
||||
self.stack[sp as usize] = val;
|
||||
self.registers[16] += 1.0;
|
||||
let last = stack[sp as usize];
|
||||
stack[sp as usize] = val;
|
||||
registers[16] += 1.0;
|
||||
Ok(last)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Result<f64, ICError> {
|
||||
self.registers[16] -= 1.0;
|
||||
let sp = (self.registers[16].round()) as i32;
|
||||
pub fn pop(&self) -> Result<f64, ICError> {
|
||||
let mut registers = self.registers.borrow_mut();
|
||||
registers[16] -= 1.0;
|
||||
let sp = (registers[16].round()) as i32;
|
||||
if sp < 0 {
|
||||
Err(ICError::StackUnderflow)
|
||||
} else if sp >= 512 {
|
||||
Err(ICError::StackOverflow)
|
||||
} else {
|
||||
let last = self.stack[sp as usize];
|
||||
let last = self.stack.borrow()[sp as usize];
|
||||
Ok(last)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn poke(&mut self, address: f64, val: f64) -> Result<f64, ICError> {
|
||||
pub fn poke(&self, address: f64, val: f64) -> Result<f64, ICError> {
|
||||
let sp = address.round() as i32;
|
||||
if !(0..512).contains(&sp) {
|
||||
Err(ICError::StackIndexOutOfRange(address))
|
||||
} else {
|
||||
let last = self.stack[sp as usize];
|
||||
self.stack[sp as usize] = val;
|
||||
let mut stack = self.stack.borrow_mut();
|
||||
let last = stack[sp as usize];
|
||||
stack[sp as usize] = val;
|
||||
Ok(last)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peek(&self) -> Result<f64, ICError> {
|
||||
let sp = (self.registers[16] - 1.0).round() as i32;
|
||||
let sp = (self.registers.borrow()[16] - 1.0).round() as i32;
|
||||
if sp < 0 {
|
||||
Err(ICError::StackUnderflow)
|
||||
} else if sp >= 512 {
|
||||
Err(ICError::StackOverflow)
|
||||
} else {
|
||||
let last = self.stack[sp as usize];
|
||||
let last = self.stack.borrow()[sp as usize];
|
||||
Ok(last)
|
||||
}
|
||||
}
|
||||
@@ -516,37 +513,49 @@ impl IC {
|
||||
} else if sp >= 512 {
|
||||
Err(ICError::StackOverflow)
|
||||
} else {
|
||||
let last = self.stack[sp as usize];
|
||||
let last = self.stack.borrow()[sp as usize];
|
||||
Ok(last)
|
||||
}
|
||||
}
|
||||
|
||||
/// processes one line of the contained program
|
||||
pub fn step(&mut self, vm: &VM, advance_ip_on_err: bool) -> Result<bool, LineError> {
|
||||
pub fn step(&self, vm: &VM, advance_ip_on_err: bool) -> Result<bool, LineError> {
|
||||
// TODO: handle sleep
|
||||
self.state = ICState::Running;
|
||||
let line = self.ip;
|
||||
self.state.replace(ICState::Running);
|
||||
let line = self.ip();
|
||||
let result = self.internal_step(vm, advance_ip_on_err);
|
||||
if let Err(error) = result {
|
||||
let error = LineError { error, line };
|
||||
self.state = ICState::Error(error.clone());
|
||||
self.state.replace(ICState::Error(error.clone()));
|
||||
Err(error)
|
||||
} else {
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
fn internal_step(&mut self, vm: &VM, advance_ip_on_err: bool) -> Result<(), ICError> {
|
||||
pub fn ip(&self) -> u32 {
|
||||
self.ip.get()
|
||||
}
|
||||
|
||||
pub fn set_ip(&self, val: u32) {
|
||||
self.ip.replace(val);
|
||||
}
|
||||
|
||||
fn internal_step(&self, vm: &VM, advance_ip_on_err: bool) -> Result<(), ICError> {
|
||||
use grammar::*;
|
||||
use ICError::*;
|
||||
|
||||
let mut next_ip = self.ip + 1;
|
||||
let mut next_ip = self.ip() + 1;
|
||||
// XXX: This closure should be replaced with a try block
|
||||
// https://github.com/rust-lang/rust/issues/31436
|
||||
let mut process_op = |this: &mut Self| -> Result<(), ICError> {
|
||||
let mut process_op = |this: &Self| -> Result<(), ICError> {
|
||||
use grammar::InstructionOp::*;
|
||||
|
||||
let line = this.program.get_line(this.ip)?;
|
||||
// force the program borrow to drop
|
||||
let line = {
|
||||
let prog = this.program.borrow();
|
||||
prog.get_line(this.ip())?.clone()
|
||||
};
|
||||
let operands = &line.operands;
|
||||
let inst = line.instruction;
|
||||
match inst {
|
||||
@@ -557,14 +566,14 @@ impl IC {
|
||||
let a = a.as_value(this, inst, 1)?;
|
||||
let now = time::OffsetDateTime::now_local()
|
||||
.unwrap_or_else(|_| time::OffsetDateTime::now_utc());
|
||||
this.state = ICState::Sleep(now, a);
|
||||
this.state.replace(ICState::Sleep(now, a));
|
||||
Ok(())
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 1)),
|
||||
}, // TODO
|
||||
Yield => match &operands[..] {
|
||||
[] => {
|
||||
this.state = ICState::Yield;
|
||||
this.state.replace(ICState::Yield);
|
||||
Ok(())
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 0)),
|
||||
@@ -585,10 +594,11 @@ impl IC {
|
||||
desired: "Number".to_owned(),
|
||||
});
|
||||
};
|
||||
if this.defines.contains_key(&ident.name) {
|
||||
let mut defines = this.defines.borrow_mut();
|
||||
if defines.contains_key(&ident.name) {
|
||||
Err(DuplicateDefine(ident.name.clone()))
|
||||
} else {
|
||||
this.defines.insert(ident.name.clone(), num.value());
|
||||
defines.insert(ident.name.clone(), num.value());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -625,7 +635,7 @@ impl IC {
|
||||
})
|
||||
}
|
||||
};
|
||||
this.aliases.insert(ident.name.clone(), alias);
|
||||
this.aliases.borrow_mut().insert(ident.name.clone(), alias);
|
||||
Ok(())
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 2)),
|
||||
@@ -671,7 +681,7 @@ impl IC {
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
let c = c.as_value(this, inst, 3)?;
|
||||
next_ip = if a == b {
|
||||
(this.ip as f64 + c) as u32
|
||||
(this.ip() as f64 + c) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -703,7 +713,7 @@ impl IC {
|
||||
let a = a.as_value(this, inst, 1)?;
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
next_ip = if a == 0.0 {
|
||||
(this.ip as f64 + b) as u32
|
||||
(this.ip() as f64 + b) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -738,7 +748,7 @@ impl IC {
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
let c = c.as_value(this, inst, 3)?;
|
||||
next_ip = if a != b {
|
||||
(this.ip as f64 + c) as u32
|
||||
(this.ip() as f64 + c) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -770,7 +780,7 @@ impl IC {
|
||||
let a = a.as_value(this, inst, 1)?;
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
next_ip = if a != 0.0 {
|
||||
(this.ip as f64 + b) as u32
|
||||
(this.ip() as f64 + b) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -805,7 +815,7 @@ impl IC {
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
let c = c.as_value(this, inst, 3)?;
|
||||
next_ip = if a < b {
|
||||
(this.ip as f64 + c) as u32
|
||||
(this.ip() as f64 + c) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -840,7 +850,7 @@ impl IC {
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
let c = c.as_value(this, inst, 3)?;
|
||||
next_ip = if a <= b {
|
||||
(this.ip as f64 + c) as u32
|
||||
(this.ip() as f64 + c) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -872,7 +882,7 @@ impl IC {
|
||||
let a = a.as_value(this, inst, 1)?;
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
next_ip = if a <= 0.0 {
|
||||
(this.ip as f64 + b) as u32
|
||||
(this.ip() as f64 + b) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -904,7 +914,7 @@ impl IC {
|
||||
let a = a.as_value(this, inst, 1)?;
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
next_ip = if a < 0.0 {
|
||||
(this.ip as f64 + b) as u32
|
||||
(this.ip() as f64 + b) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -939,7 +949,7 @@ impl IC {
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
let c = c.as_value(this, inst, 3)?;
|
||||
next_ip = if a > b {
|
||||
(this.ip as f64 + c) as u32
|
||||
(this.ip() as f64 + c) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -971,7 +981,7 @@ impl IC {
|
||||
let a = a.as_value(this, inst, 1)?;
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
next_ip = if a > 0.0 {
|
||||
(this.ip as f64 + b) as u32
|
||||
(this.ip() as f64 + b) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -1006,7 +1016,7 @@ impl IC {
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
let c = c.as_value(this, inst, 3)?;
|
||||
next_ip = if a >= b {
|
||||
(this.ip as f64 + c) as u32
|
||||
(this.ip() as f64 + c) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -1038,7 +1048,7 @@ impl IC {
|
||||
let a = a.as_value(this, inst, 1)?;
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
next_ip = if a >= 0.0 {
|
||||
(this.ip as f64 + b) as u32
|
||||
(this.ip() as f64 + b) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -1090,7 +1100,7 @@ impl IC {
|
||||
next_ip = if f64::abs(a - b)
|
||||
<= f64::max(c * f64::max(a.abs(), b.abs()), f64::EPSILON * 8.0)
|
||||
{
|
||||
(this.ip as f64 + d) as u32
|
||||
(this.ip() as f64 + d) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -1134,7 +1144,7 @@ impl IC {
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
let c = c.as_value(this, inst, 3)?;
|
||||
next_ip = if a.abs() <= f64::max(b * a.abs(), f64::EPSILON * 8.0) {
|
||||
(this.ip as f64 + c) as u32
|
||||
(this.ip() as f64 + c) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -1186,7 +1196,7 @@ impl IC {
|
||||
next_ip = if f64::abs(a - b)
|
||||
> f64::max(c * f64::max(a.abs(), b.abs()), f64::EPSILON * 8.0)
|
||||
{
|
||||
(this.ip as f64 + d) as u32
|
||||
(this.ip() as f64 + d) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -1229,7 +1239,7 @@ impl IC {
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
let c = c.as_value(this, inst, 3)?;
|
||||
next_ip = if a.abs() > f64::max(b * a.abs(), f64::EPSILON * 8.0) {
|
||||
(this.ip as f64 + c) as u32
|
||||
(this.ip() as f64 + c) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -1261,7 +1271,7 @@ impl IC {
|
||||
let (device, _connection) = d.as_device(this, inst, 1)?;
|
||||
let a = a.as_value(this, inst, 2)?;
|
||||
next_ip = if device.is_some() {
|
||||
(this.ip as f64 + a) as u32
|
||||
(this.ip() as f64 + a) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -1293,7 +1303,7 @@ impl IC {
|
||||
let (device, _connection) = d.as_device(this, inst, 1)?;
|
||||
let a = a.as_value(this, inst, 2)?;
|
||||
next_ip = if device.is_none() {
|
||||
(this.ip as f64 + a) as u32
|
||||
(this.ip() as f64 + a) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -1315,7 +1325,7 @@ impl IC {
|
||||
let a = a.as_value(this, inst, 1)?;
|
||||
let b = b.as_value(this, inst, 2)?;
|
||||
next_ip = if a.is_nan() {
|
||||
(this.ip as f64 + b) as u32
|
||||
(this.ip() as f64 + b) as u32
|
||||
} else {
|
||||
next_ip
|
||||
};
|
||||
@@ -1344,7 +1354,7 @@ impl IC {
|
||||
Jr => match &operands[..] {
|
||||
[a] => {
|
||||
let a = a.as_value(this, inst, 1)?;
|
||||
next_ip = (this.ip as f64 + a) as u32;
|
||||
next_ip = (this.ip() as f64 + a) as u32;
|
||||
Ok(())
|
||||
}
|
||||
oprs => Err(ICError::too_many_operands(oprs.len(), 1)),
|
||||
@@ -2178,7 +2188,7 @@ impl IC {
|
||||
if ic_id == &this.id {
|
||||
this.poke(addr, val)?;
|
||||
} else {
|
||||
let mut ic = vm.ics.get(ic_id).unwrap().borrow_mut();
|
||||
let ic = vm.ics.get(ic_id).unwrap().borrow();
|
||||
ic.poke(addr, val)?;
|
||||
}
|
||||
vm.set_modified(device_id);
|
||||
@@ -2206,7 +2216,7 @@ impl IC {
|
||||
if ic_id == &this.id {
|
||||
this.poke(addr, val)?;
|
||||
} else {
|
||||
let mut ic = vm.ics.get(ic_id).unwrap().borrow_mut();
|
||||
let ic = vm.ics.get(ic_id).unwrap().borrow();
|
||||
ic.poke(addr, val)?;
|
||||
}
|
||||
vm.set_modified(device_id as u32);
|
||||
@@ -2360,7 +2370,7 @@ impl IC {
|
||||
if lt == LogicType::LineNumber && this.device == device_id {
|
||||
// HACK: we can't use device.get_field as that will try to reborrow our
|
||||
// ic which will panic
|
||||
this.set_register(indirection, target, this.ip as f64)?;
|
||||
this.set_register(indirection, target, this.ip() as f64)?;
|
||||
Ok(())
|
||||
} else {
|
||||
let device = vm.get_device_same_network(this.device, device_id);
|
||||
@@ -2390,7 +2400,7 @@ impl IC {
|
||||
if lt == LogicType::LineNumber && this.device == device_id as u32 {
|
||||
// HACK: we can't use device.get_field as that will try to reborrow our
|
||||
// ic which will panic
|
||||
this.set_register(indirection, target, this.ip as f64)?;
|
||||
this.set_register(indirection, target, this.ip() as f64)?;
|
||||
Ok(())
|
||||
} else {
|
||||
let device = vm.get_device_same_network(this.device, device_id as u32);
|
||||
@@ -2419,7 +2429,7 @@ impl IC {
|
||||
if slt == SlotLogicType::LineNumber && this.device == device_id {
|
||||
// HACK: we can't use device.get_slot_field as that will try to reborrow our
|
||||
// ic which will panic
|
||||
this.set_register(indirection, target, this.ip as f64)?;
|
||||
this.set_register(indirection, target, this.ip() as f64)?;
|
||||
Ok(())
|
||||
} else {
|
||||
let device = vm.get_device_same_network(this.device, device_id);
|
||||
@@ -2536,8 +2546,8 @@ impl IC {
|
||||
};
|
||||
let result = process_op(self);
|
||||
if result.is_ok() || advance_ip_on_err {
|
||||
self.ic += 1;
|
||||
self.ip = next_ip;
|
||||
self.ic.set(self.ic.get() + 1);
|
||||
self.set_ip(next_ip);
|
||||
}
|
||||
result
|
||||
}
|
||||
@@ -2590,3 +2600,83 @@ pub fn i64_to_f64(i: i64) -> f64 {
|
||||
}
|
||||
i as f64
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::vm::VMError;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn batch_modes() -> Result<(), VMError> {
|
||||
let mut vm = VM::new();
|
||||
let ic = vm.add_ic(None).unwrap();
|
||||
let ic_id = {
|
||||
let device = vm.devices.get(&ic).unwrap();
|
||||
let device_ref = device.borrow();
|
||||
device_ref.ic.unwrap()
|
||||
};
|
||||
let ic_chip = vm.ics.get(&ic_id).unwrap().borrow();
|
||||
vm.set_code(
|
||||
ic,
|
||||
r#"lb r0 HASH("ItemActiveVent") On Sum
|
||||
#lb r1 HASH("ItemActiveVent") On Maximum
|
||||
lb r2 HASH("ItemActiveVent") On Minimum"#,
|
||||
)?;
|
||||
vm.step_ic(ic, false)?;
|
||||
let r0 = ic_chip.get_register(0, 0).unwrap();
|
||||
assert_eq!(r0, 0.0);
|
||||
vm.step_ic(ic, false)?;
|
||||
// let r1 = ic_chip.get_register(0, 1).unwrap();
|
||||
// assert_eq!(r1, f64::NEG_INFINITY);
|
||||
vm.step_ic(ic, false)?;
|
||||
let r2 = ic_chip.get_register(0, 2).unwrap();
|
||||
assert_eq!(r2, f64::INFINITY);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stack() -> Result<(), VMError> {
|
||||
let mut vm = VM::new();
|
||||
let ic = vm.add_ic(None).unwrap();
|
||||
let ic_id = {
|
||||
let device = vm.devices.get(&ic).unwrap();
|
||||
let device_ref = device.borrow();
|
||||
device_ref.ic.unwrap()
|
||||
};
|
||||
let ic_chip = vm.ics.get(&ic_id).unwrap().borrow();
|
||||
vm.set_code(
|
||||
ic,
|
||||
r#"push 100
|
||||
push 10
|
||||
pop r0
|
||||
push 1000
|
||||
peek r1
|
||||
poke 1 20
|
||||
pop r2
|
||||
"#,
|
||||
)?;
|
||||
vm.step_ic(ic, false)?;
|
||||
let stack0 = ic_chip.peek_addr(0.0)?;
|
||||
assert_eq!(stack0, 100.0);
|
||||
vm.step_ic(ic, false)?;
|
||||
let stack1 = ic_chip.peek_addr(1.0)?;
|
||||
assert_eq!(stack1, 10.0);
|
||||
vm.step_ic(ic, false)?;
|
||||
let r0 = ic_chip.get_register(0, 0).unwrap();
|
||||
assert_eq!(r0, 10.0);
|
||||
vm.step_ic(ic, false)?;
|
||||
let stack1 = ic_chip.peek_addr(1.0)?;
|
||||
assert_eq!(stack1, 1000.0);
|
||||
vm.step_ic(ic, false)?;
|
||||
let r1 = ic_chip.get_register(0, 1).unwrap();
|
||||
assert_eq!(r1, 1000.0);
|
||||
vm.step_ic(ic, false)?;
|
||||
let stack1 = ic_chip.peek_addr(1.0)?;
|
||||
assert_eq!(stack1, 20.0);
|
||||
vm.step_ic(ic, false)?;
|
||||
let r2 = ic_chip.get_register(0, 2).unwrap();
|
||||
assert_eq!(r2, 20.0);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,13 +285,11 @@ impl VM {
|
||||
device.borrow_mut().id = new_id;
|
||||
self.devices.insert(new_id, device);
|
||||
self.ics.iter().for_each(|(_id, ic)| {
|
||||
if let Ok(mut ic_ref) = ic.try_borrow_mut() {
|
||||
ic_ref.pins.iter_mut().for_each(|pin| {
|
||||
if pin.is_some_and(|d| d == old_id) {
|
||||
pin.replace(new_id);
|
||||
}
|
||||
})
|
||||
}
|
||||
ic.borrow().pins.borrow_mut().iter_mut().for_each(|pin| {
|
||||
if pin.is_some_and(|d| d == old_id) {
|
||||
pin.replace(new_id);
|
||||
}
|
||||
})
|
||||
});
|
||||
self.networks.iter().for_each(|(_net_id, net)| {
|
||||
if let Ok(mut net_ref) = net.try_borrow_mut() {
|
||||
@@ -312,15 +310,14 @@ impl VM {
|
||||
.ok_or(VMError::UnknownId(id))?
|
||||
.borrow();
|
||||
let ic_id = *device.ic.as_ref().ok_or(VMError::NoIC(id))?;
|
||||
let mut ic = self
|
||||
let ic = self
|
||||
.ics
|
||||
.get(&ic_id)
|
||||
.ok_or(VMError::UnknownIcId(ic_id))?
|
||||
.borrow_mut();
|
||||
.borrow();
|
||||
let new_prog = interpreter::Program::try_from_code(code)?;
|
||||
ic.program = new_prog;
|
||||
ic.ip = 0;
|
||||
ic.code = code.to_string();
|
||||
ic.program.replace(new_prog);
|
||||
ic.code.replace(code.to_string());
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
@@ -332,15 +329,14 @@ impl VM {
|
||||
.ok_or(VMError::UnknownId(id))?
|
||||
.borrow();
|
||||
let ic_id = *device.ic.as_ref().ok_or(VMError::NoIC(id))?;
|
||||
let mut ic = self
|
||||
let ic = self
|
||||
.ics
|
||||
.get(&ic_id)
|
||||
.ok_or(VMError::UnknownIcId(ic_id))?
|
||||
.borrow_mut();
|
||||
let new_prog = interpreter::Program::from_code_with_invalid(code);
|
||||
ic.program = new_prog;
|
||||
ic.ip = 0;
|
||||
ic.code = code.to_string();
|
||||
ic.program.replace(new_prog);
|
||||
ic.code.replace(code.to_string());
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
@@ -363,8 +359,8 @@ impl VM {
|
||||
.get(&ic_id)
|
||||
.ok_or(VMError::UnknownIcId(ic_id))?
|
||||
.clone();
|
||||
ic.borrow_mut().ic = 0;
|
||||
let result = ic.borrow_mut().step(self, advance_ip_on_err)?;
|
||||
ic.borrow().ic.replace(0);
|
||||
let result = ic.borrow().step(self, advance_ip_on_err)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
@@ -378,7 +374,7 @@ impl VM {
|
||||
.get(&ic_id)
|
||||
.ok_or(VMError::UnknownIcId(ic_id))?
|
||||
.clone();
|
||||
ic.borrow_mut().ic = 0;
|
||||
ic.borrow().ic.replace(0);
|
||||
self.set_modified(id);
|
||||
for _i in 0..128 {
|
||||
if let Err(err) = ic.borrow_mut().step(self, ignore_errors) {
|
||||
@@ -386,13 +382,15 @@ impl VM {
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
if let interpreter::ICState::Yield = ic.borrow().state {
|
||||
if let interpreter::ICState::Yield = *ic.borrow().state.borrow() {
|
||||
return Ok(false);
|
||||
} else if let interpreter::ICState::Sleep(_then, _sleep_for) = ic.borrow().state {
|
||||
} else if let interpreter::ICState::Sleep(_then, _sleep_for) =
|
||||
*ic.borrow().state.borrow()
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
ic.borrow_mut().state = interpreter::ICState::Yield;
|
||||
ic.borrow().state.replace(interpreter::ICState::Yield);
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
@@ -408,8 +406,8 @@ impl VM {
|
||||
.get(&ic_id)
|
||||
.ok_or(VMError::UnknownIcId(ic_id))?
|
||||
.clone();
|
||||
ic.borrow_mut().ic = 0;
|
||||
ic.borrow_mut().reset();
|
||||
ic.borrow().ic.replace(0);
|
||||
ic.borrow().reset();
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
@@ -506,7 +504,7 @@ impl VM {
|
||||
let Some(ic_id) = device.borrow().ic else {
|
||||
return Err(VMError::NoIC(id));
|
||||
};
|
||||
self.ics.get(&ic_id).unwrap().borrow_mut().pins[pin] = val;
|
||||
self.ics.get(&ic_id).unwrap().borrow().pins.borrow_mut()[pin] = val;
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ impl DeviceRef {
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| ic.as_ref().borrow().ip)
|
||||
.map(|ic| ic.as_ref().borrow().ip())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ impl DeviceRef {
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| ic.as_ref().borrow().ic)
|
||||
.map(|ic| ic.as_ref().borrow().ic.get())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ impl DeviceRef {
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| Stack(ic.as_ref().borrow().stack))
|
||||
.map(|ic| Stack(*ic.as_ref().borrow().stack.borrow()))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -149,44 +149,44 @@ impl DeviceRef {
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| Registers(ic.as_ref().borrow().registers))
|
||||
.map(|ic| Registers(*ic.as_ref().borrow().registers.borrow()))
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "aliases", skip_typescript)]
|
||||
pub fn ic_aliases(&self) -> JsValue {
|
||||
serde_wasm_bindgen::to_value(&self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
let aliases = &self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
self.vm
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| ic.as_ref().borrow().aliases.clone())
|
||||
}))
|
||||
.unwrap()
|
||||
.map(|ic| ic.as_ref().borrow().aliases.borrow().clone())
|
||||
});
|
||||
serde_wasm_bindgen::to_value(aliases).unwrap()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "defines", skip_typescript)]
|
||||
pub fn ic_defines(&self) -> JsValue {
|
||||
serde_wasm_bindgen::to_value(&self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
let defines = &self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
self.vm
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| ic.as_ref().borrow().defines.clone())
|
||||
}))
|
||||
.unwrap()
|
||||
.map(|ic| ic.as_ref().borrow().defines.borrow().clone())
|
||||
});
|
||||
serde_wasm_bindgen::to_value(defines).unwrap()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "pins", skip_typescript)]
|
||||
pub fn ic_pins(&self) -> JsValue {
|
||||
serde_wasm_bindgen::to_value(&self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
let pins = &self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
self.vm
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| ic.as_ref().borrow().pins)
|
||||
}))
|
||||
.unwrap()
|
||||
.map(|ic| *ic.as_ref().borrow().pins.borrow())
|
||||
});
|
||||
serde_wasm_bindgen::to_value(pins).unwrap()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "state")]
|
||||
@@ -202,19 +202,19 @@ impl DeviceRef {
|
||||
.get(ic)
|
||||
.map(|ic| ic.borrow().state.clone())
|
||||
})
|
||||
.map(|state| state.to_string())
|
||||
.map(|state| state.borrow().to_string())
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "program", skip_typescript)]
|
||||
pub fn ic_program(&self) -> JsValue {
|
||||
serde_wasm_bindgen::to_value(&self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
let prog = &self.device.borrow().ic.as_ref().and_then(|ic| {
|
||||
self.vm
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| ic.borrow().program.clone())
|
||||
}))
|
||||
.unwrap()
|
||||
.map(|ic| ic.borrow().program.borrow().clone())
|
||||
});
|
||||
serde_wasm_bindgen::to_value(prog).unwrap()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter, js_name = "code")]
|
||||
@@ -224,7 +224,7 @@ impl DeviceRef {
|
||||
.borrow()
|
||||
.ics
|
||||
.get(ic)
|
||||
.map(|ic| ic.borrow().code.clone())
|
||||
.map(|ic| ic.borrow().code.borrow().clone())
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user