Vm working. simple interface built

- still need stack view
- still ned to work with devices
This commit is contained in:
Rachel
2024-03-28 01:31:09 -07:00
parent 3047f774c5
commit baf67b2c6a
25 changed files with 2295 additions and 586 deletions

104
ic10emu/Cargo.lock generated
View File

@@ -38,6 +38,16 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
"serde",
]
[[package]]
name = "either"
version = "1.10.0"
@@ -75,10 +85,11 @@ dependencies = [
"phf_codegen",
"rand",
"regex",
"serde",
"strum",
"strum_macros",
"thiserror",
"web-time",
"time",
]
[[package]]
@@ -90,6 +101,12 @@ dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "js-sys"
version = "0.3.69"
@@ -117,6 +134,21 @@ version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num_threads"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.19.0"
@@ -205,6 +237,12 @@ dependencies = [
"siphasher",
]
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@@ -300,6 +338,26 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "serde"
version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
]
[[package]]
name = "siphasher"
version = "0.3.11"
@@ -371,6 +429,40 @@ dependencies = [
"syn 2.0.53",
]
[[package]]
name = "time"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
dependencies = [
"deranged",
"itoa",
"js-sys",
"libc",
"num-conv",
"num_threads",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
@@ -442,13 +534,3 @@ name = "wasm-bindgen-shared"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]]
name = "web-time"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
dependencies = [
"js-sys",
"wasm-bindgen",
]

View File

@@ -9,21 +9,30 @@ edition = "2021"
crate-type = ["lib"]
[dependencies]
const-crc32 = "1.3.0"
itertools = "0.12.1"
phf = "0.11.2"
rand = "0.8.5"
regex = "1.10.3"
serde = { version = "1.0.197", features = ["derive"] }
strum = { version = "0.26.2", features = ["derive", "phf", "strum_macros"] }
strum_macros = "0.26.2"
thiserror = "1.0.58"
time = { version = "0.3.34", features = [
"formatting",
"serde",
"local-offset",
] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
web-time = "1.1.0"
getrandom = { version = "0.2", features = ["js"] }
time = { version = "0.3.34", features = [
"formatting",
"serde",
"local-offset",
"wasm-bindgen",
] }
[build-dependencies]

View File

@@ -44,7 +44,7 @@ fn write_repr_enum<T: std::io::Write, I, P>(
let additional_strum = if use_phf { "#[strum(use_phf)]\n" } else { "" };
write!(
writer,
"#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash, EnumString, AsRefStr, EnumProperty, EnumIter)]\n\
"#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash, EnumString, AsRefStr, EnumProperty, EnumIter, Serialize, Deserialize)]\n\
{additional_strum}\
pub enum {name} {{\n"
)

View File

@@ -1,5 +1,5 @@
use crate::interpreter;
use crate::tokens::SplitConsecutiveIndicesExt;
use crate::tokens::{SplitConsecutiveIndicesExt, SplitConsecutiveWithIndices};
use itertools::Itertools;
use std::error::Error;
use std::fmt::Display;
@@ -16,6 +16,7 @@ pub mod generated {
use strum::EnumProperty;
use strum::EnumString;
use strum::IntoEnumIterator;
use serde::{Deserialize, Serialize};
include!(concat!(env!("OUT_DIR"), "/instructions.rs"));
include!(concat!(env!("OUT_DIR"), "/logictypes.rs"));
@@ -85,8 +86,9 @@ pub mod generated {
}
pub use generated::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParseError {
pub line: usize,
pub start: usize,
@@ -233,29 +235,15 @@ impl FromStr for Instruction {
})
}
}?;
let mut operand_tokens = Vec::new();
let mut string_start = None;
for (index, token) in tokens_iter {
if token.starts_with("HASH(\"") {
string_start = Some(index);
}
if let Some(start) = string_start {
if token.ends_with("\")") {
operand_tokens.push((start, &s[start..(index + token.len())]));
string_start = None;
}
} else {
operand_tokens.push((index, token));
}
}
let operands = operand_tokens
.into_iter()
let operands = get_operand_tokens(s, tokens_iter)
.iter()
.map(|(index, token)| {
token
.parse::<Operand>()
.map_err(|e| e.offset(index).span(token.len()))
.map_err(|e| e.offset(*index).span(token.len()))
})
.collect::<Result<Vec<_>, ParseError>>()?;
.try_collect()?;
Ok(Instruction {
instruction,
operands,
@@ -263,14 +251,33 @@ impl FromStr for Instruction {
}
}
#[derive(PartialEq, Debug, Clone, Copy)]
fn get_operand_tokens<'a>(s: &'a str, tokens_iter: SplitConsecutiveWithIndices<'a>) -> Vec<(usize, &'a str)> {
let mut operand_tokens = Vec::with_capacity(8);
let mut string_start = None;
for (index, token) in tokens_iter {
if token.starts_with("HASH(\"") {
string_start = Some(index);
}
if let Some(start) = string_start {
if token.ends_with("\")") {
operand_tokens.push((start, &s[start..(index + token.len())]));
string_start = None;
}
} else {
operand_tokens.push((index, token));
}
}
operand_tokens
}
#[derive(PartialEq, Debug, Clone, Copy, Serialize, Deserialize)]
pub enum Device {
Db,
Numbered(u32),
Indirect { indirection: u32, target: u32 },
}
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub enum Operand {
RegisterSpec {
indirection: u32,
@@ -349,7 +356,7 @@ impl Operand {
) -> Result<(Option<u16>, Option<u32>), interpreter::ICError> {
match &self {
&Operand::DeviceSpec { device, connection } => match device {
Device::Db => Ok((Some(ic.id), *connection)),
Device::Db => Ok((Some(ic.device), *connection)),
Device::Numbered(p) => {
let dp = ic
.pins
@@ -598,6 +605,7 @@ impl FromStr for Operand {
.collect::<String>();
if !float_str.is_empty() {
if rest_iter.peek() == Some(&&'.') {
rest_iter.next();
let decimal_str = rest_iter
.take_while_ref(|c| c.is_digit(10))
.collect::<String>();
@@ -684,7 +692,7 @@ impl FromStr for Label {
}
}
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct Identifier {
// #[rust_sitter::leaf(pattern = r"[a-zA-Z_.][\w\d.]*", transform = |id| id.to_string())]
pub name: String,
@@ -732,7 +740,7 @@ impl FromStr for Identifier {
}
}
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub enum Number {
Float(f64),
Binary(f64),
@@ -757,7 +765,6 @@ impl Number {
#[cfg(test)]
mod tests {
use super::generated::*;
use super::*;
#[test]

File diff suppressed because it is too large Load Diff

View File

@@ -1,47 +1,56 @@
use core::f64;
use std::collections::{HashMap, HashSet};
use std::{
cell::RefCell,
collections::{HashMap, HashSet},
rc::Rc,
};
mod grammar;
mod interpreter;
pub mod grammar;
pub mod interpreter;
mod rand_mscorlib;
mod tokens;
pub mod tokens;
use grammar::{BatchMode, LogicType, ReagentMode, SlotLogicType};
use interpreter::ICError;
use interpreter::{ICError, LineError};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Error, Debug)]
#[derive(Error, Debug, Serialize, Deserialize)]
pub enum VMError {
#[error("Device with id '{0}' does not exist")]
UnknownId(u16),
#[error("IC with id '{0}' does not exist")]
UnknownIcId(u16),
#[error("Device with id '{0}' does not have a IC Slot")]
NoIC(u16),
#[error("IC encoutered an error: {0}")]
ICError(#[from] ICError),
#[error("IC encoutered an error: {0}")]
LineError(#[from] LineError),
#[error("Invalid network ID {0}")]
InvalidNetwork(u16),
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum FieldType {
Read,
Write,
ReadWrite,
}
#[derive(Debug)]
#[derive(Debug, Serialize, Deserialize)]
pub struct LogicField {
pub field_type: FieldType,
pub value: f64,
}
#[derive(Debug, Default)]
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct Slot {
pub fields: HashMap<grammar::SlotLogicType, LogicField>,
}
#[derive(Debug, Default, Clone, Copy)]
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
pub enum Connection {
CableNetwork(Option<u16>),
#[default]
@@ -56,12 +65,12 @@ pub struct Device {
pub fields: HashMap<grammar::LogicType, LogicField>,
pub slots: Vec<Slot>,
pub reagents: HashMap<ReagentMode, HashMap<i32, f64>>,
pub ic: Option<interpreter::IC>,
pub ic: Option<u16>,
pub connections: [Connection; 8],
pub prefab_hash: Option<i32>,
}
#[derive(Debug)]
#[derive(Debug, Serialize, Deserialize)]
pub struct Network {
pub devices: HashSet<u16>,
pub channels: [f64; 8],
@@ -74,7 +83,7 @@ struct IdSequenceGenerator {
impl Default for IdSequenceGenerator {
fn default() -> Self {
IdSequenceGenerator { next: 1 }
IdSequenceGenerator { next: 0 }
}
}
@@ -88,13 +97,13 @@ impl IdSequenceGenerator {
#[derive(Debug)]
pub struct VM {
pub ics: HashSet<u16>,
pub devices: HashMap<u16, Device>,
pub networks: HashMap<u16, Network>,
pub ics: HashMap<u16, Rc<RefCell<interpreter::IC>>>,
pub devices: HashMap<u16, Rc<RefCell<Device>>>,
pub networks: HashMap<u16, Rc<RefCell<Network>>>,
pub default_network: u16,
id_gen: IdSequenceGenerator,
network_id_gen: IdSequenceGenerator,
random: crate::rand_mscorlib::Random,
random: Rc<RefCell<crate::rand_mscorlib::Random>>,
}
impl Default for Network {
@@ -146,7 +155,7 @@ impl Network {
impl Device {
pub fn new(id: u16) -> Self {
Device {
let mut device = Device {
id,
name: None,
name_hash: None,
@@ -156,12 +165,36 @@ impl Device {
ic: None,
connections: [Connection::default(); 8],
prefab_hash: None,
}
};
device.connections[0] = Connection::CableNetwork(None);
device
}
pub fn with_ic(id: u16) -> Self {
pub fn with_ic(id: u16, ic: u16) -> Self {
let mut device = Device::new(id);
device.ic = Some(interpreter::IC::new(id));
device.ic = Some(ic);
device.fields.insert(
LogicType::Setting,
LogicField {
field_type: FieldType::ReadWrite,
value: 0.0,
},
);
device.fields.insert(
LogicType::Error,
LogicField {
field_type: FieldType::ReadWrite,
value: 0.0,
},
);
device.fields.insert(
LogicType::PrefabHash,
LogicField {
field_type: FieldType::Read,
value: -128473777.0,
},
);
device.prefab_hash = Some(-128473777);
device
}
@@ -262,19 +295,19 @@ impl VM {
pub fn new() -> Self {
let id_gen = IdSequenceGenerator::default();
let mut network_id_gen = IdSequenceGenerator::default();
let default_network = Network::default();
let default_network = Rc::new(RefCell::new(Network::default()));
let mut networks = HashMap::new();
let default_network_key = network_id_gen.next();
networks.insert(default_network_key, default_network);
let mut vm = VM {
ics: HashSet::new(),
ics: HashMap::new(),
devices: HashMap::new(),
networks,
default_network: default_network_key,
id_gen,
network_id_gen,
random: crate::rand_mscorlib::Random::new(),
random: Rc::new(RefCell::new(crate::rand_mscorlib::Random::new())),
};
let _ = vm.add_ic(None);
vm
@@ -284,8 +317,11 @@ impl VM {
Device::new(self.id_gen.next())
}
fn new_ic(&mut self) -> Device {
Device::with_ic(self.id_gen.next())
fn new_ic(&mut self) -> (Device, interpreter::IC) {
let id = self.id_gen.next();
let ic = interpreter::IC::new(id, id);
let device = Device::with_ic(id, id);
(device, ic)
}
pub fn add_device(&mut self, network: Option<u16>) -> Result<u16, VMError> {
@@ -314,7 +350,15 @@ impl VM {
});
}
let id = device.id;
self.devices.insert(id, device);
self.devices.insert(id, Rc::new(RefCell::new(device)));
let _ = self.add_device_to_network(
id,
if let Some(network) = network {
network
} else {
self.default_network
},
);
Ok(id)
}
@@ -324,7 +368,7 @@ impl VM {
return Err(VMError::InvalidNetwork(*n));
}
}
let mut device = self.new_ic();
let (mut device, ic) = self.new_ic();
if let Some(first_network) = device
.connections
.iter_mut()
@@ -344,45 +388,117 @@ impl VM {
});
}
let id = device.id;
self.devices.insert(id, device);
self.ics.insert(id);
let ic_id = ic.id;
self.devices.insert(id, Rc::new(RefCell::new(device)));
self.ics.insert(ic_id, Rc::new(RefCell::new(ic)));
let _ = self.add_device_to_network(
id,
if let Some(network) = network {
network
} else {
self.default_network
},
);
Ok(id)
}
pub fn add_network(&mut self) -> u16 {
let next_id = self.network_id_gen.next();
self.networks.insert(next_id, Network::default());
self.networks
.insert(next_id, Rc::new(RefCell::new(Network::default())));
next_id
}
pub fn get_default_network(&mut self) -> &mut Network {
self.networks.get_mut(&self.default_network).unwrap()
pub fn get_default_network(&self) -> Rc<RefCell<Network>> {
self.networks.get(&self.default_network).cloned().unwrap()
}
pub fn get_network(&mut self, id: u16) -> Option<&mut Network> {
self.networks.get_mut(&id)
pub fn get_network(&self, id: u16) -> Option<Rc<RefCell<Network>>> {
self.networks.get(&id).cloned()
}
pub fn remove_ic(&mut self, id: u16) {
if self.ics.remove(&id) {
if self.ics.remove(&id).is_some() {
self.devices.remove(&id);
}
}
pub fn set_code(&mut self, id: u16, code: &str) -> Result<bool, VMError> {
let device = self.devices.get_mut(&id).ok_or(VMError::UnknownId(id))?;
let ic = device.ic.as_mut().ok_or(VMError::NoIC(id))?;
pub fn set_code(&self, id: u16, code: &str) -> Result<bool, VMError> {
let device = self
.devices
.get(&id)
.ok_or(VMError::UnknownId(id))?
.borrow();
let ic_id = *device.ic.as_ref().ok_or(VMError::NoIC(id))?;
let mut ic = self
.ics
.get(&ic_id)
.ok_or(VMError::UnknownIcId(ic_id))?
.borrow_mut();
let new_prog = interpreter::Program::try_from_code(code)?;
ic.program = new_prog;
ic.ip = 0;
ic.code = code.to_string();
Ok(true)
}
pub fn get_device(&mut self, id: u16) -> Option<&mut Device> {
self.devices.get_mut(&id)
pub fn step_ic(&self, id: u16) -> Result<bool, VMError> {
let device = self.devices.get(&id).ok_or(VMError::UnknownId(id))?.clone();
let ic_id = *device.borrow().ic.as_ref().ok_or(VMError::NoIC(id))?;
let ic = self
.ics
.get(&ic_id)
.ok_or(VMError::UnknownIcId(ic_id))?
.clone();
ic.borrow_mut().ic = 0;
let result = ic.borrow_mut().step(self)?;
Ok(result)
}
pub fn get_device_same_network(&mut self, source: u16, other: u16) -> Option<&mut Device> {
/// returns true if exacuted 128 lines, false if returned early.
pub fn run_ic(&self, id: u16, ignore_errors: bool) -> Result<bool, VMError> {
let device = self.devices.get(&id).ok_or(VMError::UnknownId(id))?.clone();
let ic_id = *device.borrow().ic.as_ref().ok_or(VMError::NoIC(id))?;
let ic = self
.ics
.get(&ic_id)
.ok_or(VMError::UnknownIcId(ic_id))?
.clone();
ic.borrow_mut().ic = 0;
for _i in 0..128 {
if let Err(err) = ic.borrow_mut().step(self) {
if !ignore_errors {
return Err(err.into());
}
}
if let interpreter::ICState::Yield = ic.borrow().state {
return Ok(false);
} else if let interpreter::ICState::Sleep(_then, _sleep_for) = ic.borrow().state {
return Ok(false);
}
}
ic.borrow_mut().state = interpreter::ICState::Yield;
Ok(true)
}
pub fn reset_ic(&self, id: u16) -> Result<bool, VMError> {
let device = self.devices.get(&id).ok_or(VMError::UnknownId(id))?.clone();
let ic_id = *device.borrow().ic.as_ref().ok_or(VMError::NoIC(id))?;
let ic = self
.ics
.get(&ic_id)
.ok_or(VMError::UnknownIcId(ic_id))?
.clone();
ic.borrow_mut().ic = 0;
ic.borrow_mut().reset();
Ok(true)
}
pub fn get_device(&self, id: u16) -> Option<Rc<RefCell<Device>>> {
self.devices.get(&id).cloned()
}
pub fn get_device_same_network(&self, source: u16, other: u16) -> Option<Rc<RefCell<Device>>> {
if self.devices_on_same_network(&[source, other]) {
self.get_device(other)
} else {
@@ -395,29 +511,41 @@ impl VM {
.networks
.get(&(id as u16))
.ok_or(ICError::BadNetworkId(id as u32))?;
Ok(network.channels[channel])
Ok(network.borrow().channels[channel])
}
pub fn set_network_channel(&mut self, id: usize, channel: usize, val: f64) -> Result<(), ICError> {
pub fn set_network_channel(&self, id: usize, channel: usize, val: f64) -> Result<(), ICError> {
let network = self
.networks
.get_mut(&(id as u16))
.get(&(id as u16))
.ok_or(ICError::BadNetworkId(id as u32))?;
network.channels[channel] = val;
network.borrow_mut().channels[channel] = val;
Ok(())
}
pub fn devices_on_same_network(&self, ids: &[u16]) -> bool {
for (_id, net) in self.networks.iter() {
if net.contains(ids) {
if net.borrow().contains(ids) {
return true;
}
}
false
}
fn add_device_to_network(&self, id: u16, network_id: u16) -> Result<bool, VMError> {
if !self.devices.contains_key(&id) {
return Err(VMError::UnknownId(id));
};
if let Some(network) = self.networks.get(&network_id) {
network.borrow_mut().add(id);
Ok(true)
} else {
Err(VMError::InvalidNetwork(network_id))
}
}
pub fn set_batch_device_field(
&mut self,
&self,
source: u16,
prefab: f64,
typ: LogicType,
@@ -425,14 +553,19 @@ impl VM {
) -> Result<(), ICError> {
let networks = &self.networks;
self.devices
.iter_mut()
.iter()
.map(|(id, device)| {
if device.fields.get(&LogicType::PrefabHash).map(|f| f.value) == Some(prefab)
if device
.borrow()
.fields
.get(&LogicType::PrefabHash)
.map(|f| f.value)
== Some(prefab)
&& networks
.iter()
.any(|(_net_id, net)| net.contains(&[source, *id]))
.any(|(_net_id, net)| net.borrow().contains(&[source, *id]))
{
device.set_field(typ, val)
device.clone().borrow_mut().set_field(typ, val)
} else {
Ok(())
}
@@ -441,7 +574,7 @@ impl VM {
}
pub fn set_batch_device_slot_field(
&mut self,
&self,
source: u16,
prefab: f64,
index: f64,
@@ -450,14 +583,19 @@ impl VM {
) -> Result<(), ICError> {
let networks = &self.networks;
self.devices
.iter_mut()
.iter()
.map(|(id, device)| {
if device.fields.get(&LogicType::PrefabHash).map(|f| f.value) == Some(prefab)
if device
.borrow()
.fields
.get(&LogicType::PrefabHash)
.map(|f| f.value)
== Some(prefab)
&& networks
.iter()
.any(|(_net_id, net)| net.contains(&[source, *id]))
.any(|(_net_id, net)| net.borrow().contains(&[source, *id]))
{
device.set_slot_field(index, typ, val)
device.borrow_mut().set_slot_field(index, typ, val)
} else {
Ok(())
}
@@ -466,7 +604,7 @@ impl VM {
}
pub fn set_batch_name_device_field(
&mut self,
&self,
source: u16,
prefab: f64,
name: f64,
@@ -475,15 +613,20 @@ impl VM {
) -> Result<(), ICError> {
let networks = &self.networks;
self.devices
.iter_mut()
.iter()
.map(|(id, device)| {
if device.fields.get(&LogicType::PrefabHash).map(|f| f.value) == Some(prefab)
&& Some(name) == device.name_hash
if device
.borrow()
.fields
.get(&LogicType::PrefabHash)
.map(|f| f.value)
== Some(prefab)
&& Some(name) == device.borrow().name_hash
&& networks
.iter()
.any(|(_net_id, net)| net.contains(&[source, *id]))
.any(|(_net_id, net)| net.borrow().contains(&[source, *id]))
{
device.set_field(typ, val)
device.borrow_mut().set_field(typ, val)
} else {
Ok(())
}
@@ -492,7 +635,7 @@ impl VM {
}
pub fn get_batch_device_field(
&mut self,
&self,
source: u16,
prefab: f64,
typ: LogicType,
@@ -501,14 +644,19 @@ impl VM {
let networks = &self.networks;
let samples = self
.devices
.iter_mut()
.iter()
.map(|(id, device)| {
if device.fields.get(&LogicType::PrefabHash).map(|f| f.value) == Some(prefab)
if device
.borrow()
.fields
.get(&LogicType::PrefabHash)
.map(|f| f.value)
== Some(prefab)
&& networks
.iter()
.any(|(_net_id, net)| net.contains(&[source, *id]))
.any(|(_net_id, net)| net.borrow().contains(&[source, *id]))
{
device.get_field(typ).map(|val| Some(val))
device.borrow_mut().get_field(typ).map(|val| Some(val))
} else {
Ok(None)
}
@@ -535,7 +683,7 @@ impl VM {
}
pub fn get_batch_name_device_field(
&mut self,
&self,
source: u16,
prefab: f64,
name: f64,
@@ -545,15 +693,20 @@ impl VM {
let networks = &self.networks;
let samples = self
.devices
.iter_mut()
.iter()
.map(|(id, device)| {
if device.fields.get(&LogicType::PrefabHash).map(|f| f.value) == Some(prefab)
&& Some(name) == device.name_hash
if device
.borrow()
.fields
.get(&LogicType::PrefabHash)
.map(|f| f.value)
== Some(prefab)
&& Some(name) == device.borrow().name_hash
&& networks
.iter()
.any(|(_net_id, net)| net.contains(&[source, *id]))
.any(|(_net_id, net)| net.borrow().contains(&[source, *id]))
{
device.get_field(typ).map(|val| Some(val))
device.borrow().get_field(typ).map(|val| Some(val))
} else {
Ok(None)
}
@@ -580,7 +733,7 @@ impl VM {
}
pub fn get_batch_name_device_slot_field(
&mut self,
&self,
source: u16,
prefab: f64,
name: f64,
@@ -591,15 +744,23 @@ impl VM {
let networks = &self.networks;
let samples = self
.devices
.iter_mut()
.iter()
.map(|(id, device)| {
if device.fields.get(&LogicType::PrefabHash).map(|f| f.value) == Some(prefab)
&& Some(name) == device.name_hash
if device
.borrow()
.fields
.get(&LogicType::PrefabHash)
.map(|f| f.value)
== Some(prefab)
&& Some(name) == device.borrow().name_hash
&& networks
.iter()
.any(|(_net_id, net)| net.contains(&[source, *id]))
.any(|(_net_id, net)| net.borrow().contains(&[source, *id]))
{
device.get_slot_field(index, typ).map(|val| Some(val))
device
.borrow()
.get_slot_field(index, typ)
.map(|val| Some(val))
} else {
Ok(None)
}
@@ -626,7 +787,7 @@ impl VM {
}
pub fn get_batch_device_slot_field(
&mut self,
&self,
source: u16,
prefab: f64,
index: f64,
@@ -636,14 +797,22 @@ impl VM {
let networks = &self.networks;
let samples = self
.devices
.iter_mut()
.iter()
.map(|(id, device)| {
if device.fields.get(&LogicType::PrefabHash).map(|f| f.value) == Some(prefab)
if device
.borrow()
.fields
.get(&LogicType::PrefabHash)
.map(|f| f.value)
== Some(prefab)
&& networks
.iter()
.any(|(_net_id, net)| net.contains(&[source, *id]))
.any(|(_net_id, net)| net.borrow().contains(&[source, *id]))
{
device.get_slot_field(index, typ).map(|val| Some(val))
device
.borrow()
.get_slot_field(index, typ)
.map(|val| Some(val))
} else {
Ok(None)
}

View File

@@ -1,16 +1,15 @@
use std::usize;
const MSEED: i32 = 161803398;
// const MZ: i32 = 0;
// const MZ: i32 = 0;
#[derive(Debug)]
pub struct Random {
inext: i32,
inextp: i32,
inext: usize,
inextp: usize,
seed_array: [i32; 56],
}
/// Partial implementation of mscorlib System.Random
/// https://github.com/microsoft/referencesource/blob/master/mscorlib/system/random.cs#L94
impl Random {
@@ -29,20 +28,20 @@ impl Random {
seed_array[55] = mj;
let mut mk: i32 = 1;
for i in 1_usize..55 {
let ii = (21 * i) % 55;
for i in 1..55 {
let ii = 21 * i % 55;
seed_array[ii] = mk;
mk = mj - mk;
mk = mj.wrapping_sub(mk);
if mk < 0 {
mk += i32::MAX;
mk = mk.wrapping_add(i32::MAX);
}
mj = seed_array[ii];
}
for _k in 1_usize..5 {
for i in 1_usize..56 {
seed_array[i] -= seed_array[1 + (i + 30) % 55];
seed_array[i] = seed_array[i].wrapping_sub(seed_array[1 + (i + 30) % 55]);
if seed_array[i] < 0 {
seed_array[i] += i32::MAX;
seed_array[i] = seed_array[i].wrapping_add(i32::MAX);
}
}
}
@@ -64,28 +63,24 @@ impl Random {
let mut inext = self.inext;
let mut inextp = self.inextp;
if {
inext += 1;
inext
} >= 56
{
inext += 1;
if inext >= 56 {
inext = 1;
}
if {
inextp += 1;
inextp
} >= 56
{
inextp += 1;
if inextp >= 56 {
inextp = 1;
}
let mut retval = self.seed_array[inext as usize] - self.seed_array[inextp as usize];
let mut retval =
self.seed_array[inext as usize].wrapping_sub(self.seed_array[inextp as usize]);
if retval == i32::MAX {
retval -= 1;
}
if retval < 0 {
retval += i32::MAX;
retval = retval.wrapping_add(i32::MAX);
}
self.seed_array[inext as usize] = retval;
@@ -103,6 +98,26 @@ impl Random {
pub fn next_f64(&mut self) -> f64 {
self.sample()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn create() {
let mut rand = Random::with_seed(0);
assert_eq!(rand.next(), 1559595546);
assert_eq!(rand.next(), 1755192844);
}
#[test]
fn verify() {
let mut rand = Random::with_seed(1919810);
assert_eq!(rand.next(), 147482110);
assert_eq!(rand.next(), 1747108798);
assert_eq!(rand.next(), 1937076328);
assert_eq!(rand.next(), 924982271);
assert_eq!(rand.next_f64(), 0.044092261252967765);
assert_eq!(rand.next(), 659561101);
}
}

View File

@@ -47,14 +47,16 @@ impl<'a> Iterator for SplitConsecutiveWithIndices<'a> {
}
} else {
let s = &self.haystack[self.start..start];
let index = self.start;
self.start = start;
Some((self.start, s))
Some((index, s))
}
}
None => {
let s = &self.haystack[self.start..];
let index = self.start;
self.start = self.haystack.len();
Some((self.start, s))
Some((index, s))
}
}
}

View File

@@ -0,0 +1,147 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div class=\"dni-plaintext\"><pre>[ 1559595546, 1755192844 ]</pre></div><style>\r\n",
".dni-code-hint {\r\n",
" font-style: italic;\r\n",
" overflow: hidden;\r\n",
" white-space: nowrap;\r\n",
"}\r\n",
".dni-treeview {\r\n",
" white-space: nowrap;\r\n",
"}\r\n",
".dni-treeview td {\r\n",
" vertical-align: top;\r\n",
" text-align: start;\r\n",
"}\r\n",
"details.dni-treeview {\r\n",
" padding-left: 1em;\r\n",
"}\r\n",
"table td {\r\n",
" text-align: start;\r\n",
"}\r\n",
"table tr { \r\n",
" vertical-align: top; \r\n",
" margin: 0em 0px;\r\n",
"}\r\n",
"table tr td pre \r\n",
"{ \r\n",
" vertical-align: top !important; \r\n",
" margin: 0em 0px !important;\r\n",
"} \r\n",
"table th {\r\n",
" text-align: start;\r\n",
"}\r\n",
"</style>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"var rand = new System.Random(0);\n",
"int[] two_rands = [rand.Next(), rand.Next()];\n",
"\n",
"two_rands"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div class=\"dni-plaintext\"><pre>[ 147482110, 1747108798, 1937076328, 924982271, 0.044092261252967765, 659561101 ]</pre></div><style>\r\n",
".dni-code-hint {\r\n",
" font-style: italic;\r\n",
" overflow: hidden;\r\n",
" white-space: nowrap;\r\n",
"}\r\n",
".dni-treeview {\r\n",
" white-space: nowrap;\r\n",
"}\r\n",
".dni-treeview td {\r\n",
" vertical-align: top;\r\n",
" text-align: start;\r\n",
"}\r\n",
"details.dni-treeview {\r\n",
" padding-left: 1em;\r\n",
"}\r\n",
"table td {\r\n",
" text-align: start;\r\n",
"}\r\n",
"table tr { \r\n",
" vertical-align: top; \r\n",
" margin: 0em 0px;\r\n",
"}\r\n",
"table tr td pre \r\n",
"{ \r\n",
" vertical-align: top !important; \r\n",
" margin: 0em 0px !important;\r\n",
"} \r\n",
"table th {\r\n",
" text-align: start;\r\n",
"}\r\n",
"</style>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"var rand = new System.Random(1919810);\n",
"double[] samples = [rand.Next(), rand.Next(), rand.Next(), rand.Next(), rand.NextDouble(), rand.Next()];\n",
"\n",
"samples"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".NET (C#)",
"language": "C#",
"name": ".net-csharp"
},
"language_info": {
"name": "polyglot-notebook"
},
"polyglot_notebook": {
"kernelInfo": {
"defaultKernelName": "csharp",
"items": [
{
"aliases": [],
"name": "csharp"
}
]
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}