diff --git a/Cargo.toml b/Cargo.toml index 0248d63242b98e3d6be3d4343d64eb6adf87b356..f32b593bd1b50de04db616b3f2c5057863479f39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ maplit = "1.0.2" derive_more = "0.99.2" # runtime +serde = { version = "1.0.112", features = ["derive"] } getrandom = "0.1.14" # tiny crate. used to guess controller-id take_mut = "0.2.2" indexmap = "1.3.0" # hashsets/hashmaps with efficient arbitrary element removal @@ -24,7 +25,7 @@ mio = "0.6.21" # migrate to mio v0.7.0 when it stabilizes mio-extras = "2.0.6" # protocol -id-arena = "2.2.1" +# id-arena = "2.2.1" backtrace = "0.3" [dev-dependencies] diff --git a/README.md b/README.md index 7014917d77d9dceecefbfc3e70c78d1eedce037f..f18a11eecd15e0af40fc59a9a19e9b76bfd55497 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,11 @@ -# Reowolf Implementation +# Reowolf 1.0 Implementation ## Compilation instructions +1. Install the latest stable Rust toolchain using Rustup. See https://rustup.rs/ for further instructions. +2. Run `cargo build --release` to download source dependencies, and compile the library with release-level optimizations. + - The resulting dylib can be found in target/release/, to be used with the header file reowolf.h. + - Note: A list of immediate ancestor dependencies is visible in Cargo.toml. + - Note: Run `cargo test --release` to run unit tests with release-level optimizations. -1. Install the Rust toolchain, using Rustup. See https://rustup.rs/ for further instructions. -2. Run `cargo test` to download dependencies, compile the project, and run the tests. - +## Structure +- The user-facing API is visible in src/runtime/connector.rs diff --git a/src/common.rs b/src/common.rs index afe9562fb9c70af054cbc6325970412387dffbb9..d3e98a1106c63286875543bd83c8429075bc061e 100644 --- a/src/common.rs +++ b/src/common.rs @@ -35,6 +35,18 @@ pub struct PortId { #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] pub struct Payload(Arc>); +impl serde::Serialize for Payload { + fn serialize( + &self, + serializer: S, + ) -> std::result::Result<::Ok, ::Error> + where + S: serde::Serializer, + { + let inner: &Vec = &self.0; + inner.serialize(serializer) + } +} /// This is a unique identifier for a channel (i.e., port). #[derive(Debug, Eq, PartialEq, Clone, Hash, Copy, Ord, PartialOrd)] @@ -49,9 +61,9 @@ pub enum Polarity { Getter, // input port (from the perspective of the component) } -#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)] +#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone, serde::Serialize)] #[repr(C)] -pub struct Port(pub usize); // ports are COPY +pub struct Port(pub u32); // ports are COPY #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum MainComponentErr { @@ -157,10 +169,10 @@ impl Debug for Port { } } impl Port { - pub fn from_raw(raw: usize) -> Self { + pub fn from_raw(raw: u32) -> Self { Self(raw) } - pub fn to_raw(self) -> usize { + pub fn to_raw(self) -> u32 { self.0 } pub fn to_token(self) -> mio::Token { diff --git a/src/protocol/arena.rs b/src/protocol/arena.rs new file mode 100644 index 0000000000000000000000000000000000000000..e83360611516969e9e1e97dfff8898cea39fb9a3 --- /dev/null +++ b/src/protocol/arena.rs @@ -0,0 +1,57 @@ +use core::hash::Hash; +use core::marker::PhantomData; + +#[derive(Debug, serde::Serialize)] +pub struct Id { + index: u32, + _phantom: PhantomData, +} +impl Clone for Id { + fn clone(&self) -> Self { + *self + } +} +impl Copy for Id {} +impl PartialEq for Id { + fn eq(&self, other: &Self) -> bool { + self.index.eq(&other.index) + } +} +impl Eq for Id {} +impl Hash for Id { + fn hash(&self, h: &mut H) { + self.index.hash(h); + } +} + +pub struct Arena { + store: Vec, +} +impl Arena { + pub fn new() -> Self { + Self { store: vec![] } + } + pub fn alloc_with_id(&mut self, f: impl FnOnce(Id) -> T) -> Id { + use std::convert::TryFrom; + let id = Id { + index: u32::try_from(self.store.len()).expect("Out of capacity!"), + _phantom: Default::default(), + }; + self.store.push(f(id)); + id + } + pub fn iter(&self) -> impl Iterator, &T)> { + (0..).map(|index| Id { index, _phantom: Default::default() }).zip(self.store.iter()) + } +} +impl core::ops::Index> for Arena { + type Output = T; + fn index(&self, id: Id) -> &Self::Output { + self.store.index(id.index as usize) + } +} +impl core::ops::IndexMut> for Arena { + fn index_mut(&mut self, id: Id) -> &mut Self::Output { + self.store.index_mut(id.index as usize) + } +} diff --git a/src/protocol/ast.rs b/src/protocol/ast.rs index 906334e8f99762e6dc18d200efae566354c12177..b9878be3d35a35deabb372ceea4df0fc82e40d89 100644 --- a/src/protocol/ast.rs +++ b/src/protocol/ast.rs @@ -2,7 +2,7 @@ use std::fmt; use std::fmt::{Debug, Display, Formatter}; use std::ops::{Index, IndexMut}; -use id_arena::{Arena, Id}; +use super::arena::{Arena, Id}; use crate::protocol::inputsource::*; @@ -39,7 +39,7 @@ impl ExternalIdentifierId { #[derive(Debug, Clone, Copy, PartialEq)] pub struct TypeAnnotationId(Id); -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize)] pub struct VariableId(Id); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -60,7 +60,7 @@ impl LocalId { } } -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize)] pub struct DefinitionId(Id); #[derive(Debug, Clone, Copy, PartialEq)] @@ -99,7 +99,7 @@ impl PrimitiveId { } } -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize)] pub struct StatementId(Id); #[derive(Debug, Clone, Copy, PartialEq)] diff --git a/src/protocol/eval.rs b/src/protocol/eval.rs index 4fa17c5a2eede0bf1999d491f20214461f3fb0b3..84d71a8d02bac4d9c786e41763b7158cf1f7f31b 100644 --- a/src/protocol/eval.rs +++ b/src/protocol/eval.rs @@ -28,7 +28,7 @@ trait ValueImpl { fn is_type_compatible(&self, t: &Type) -> bool; } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub enum Value { Input(InputValue), Output(OutputValue), @@ -885,7 +885,7 @@ impl Display for Value { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct InputValue(pub Port); impl Display for InputValue { @@ -910,7 +910,7 @@ impl ValueImpl for InputValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct OutputValue(pub Port); impl Display for OutputValue { @@ -935,7 +935,7 @@ impl ValueImpl for OutputValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct MessageValue(pub Option); impl Display for MessageValue { @@ -970,7 +970,7 @@ impl ValueImpl for MessageValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct BooleanValue(bool); impl Display for BooleanValue { @@ -999,7 +999,7 @@ impl ValueImpl for BooleanValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct ByteValue(i8); impl Display for ByteValue { @@ -1027,7 +1027,7 @@ impl ValueImpl for ByteValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct ShortValue(i16); impl Display for ShortValue { @@ -1054,7 +1054,7 @@ impl ValueImpl for ShortValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct IntValue(i32); impl Display for IntValue { @@ -1080,7 +1080,7 @@ impl ValueImpl for IntValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct LongValue(i64); impl Display for LongValue { @@ -1105,7 +1105,7 @@ impl ValueImpl for LongValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct InputArrayValue(Vec); impl Display for InputArrayValue { @@ -1139,7 +1139,7 @@ impl ValueImpl for InputArrayValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct OutputArrayValue(Vec); impl Display for OutputArrayValue { @@ -1173,7 +1173,7 @@ impl ValueImpl for OutputArrayValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct MessageArrayValue(Vec); impl Display for MessageArrayValue { @@ -1207,7 +1207,7 @@ impl ValueImpl for MessageArrayValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct BooleanArrayValue(Vec); impl Display for BooleanArrayValue { @@ -1241,7 +1241,7 @@ impl ValueImpl for BooleanArrayValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct ByteArrayValue(Vec); impl Display for ByteArrayValue { @@ -1275,7 +1275,7 @@ impl ValueImpl for ByteArrayValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct ShortArrayValue(Vec); impl Display for ShortArrayValue { @@ -1309,7 +1309,7 @@ impl ValueImpl for ShortArrayValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct IntArrayValue(Vec); impl Display for IntArrayValue { @@ -1343,7 +1343,7 @@ impl ValueImpl for IntArrayValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct LongArrayValue(Vec); impl Display for LongArrayValue { @@ -1377,7 +1377,7 @@ impl ValueImpl for LongArrayValue { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] struct Store { map: HashMap, } @@ -1610,7 +1610,7 @@ pub enum EvalContinuation { Put(Value, Value), } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct Prompt { definition: DefinitionId, store: Store, diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 8eaf5e1398e1462da4be7eace773cb7c61443368..948853abb2d906743f90a5f803cb25a5a6a4af03 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -1,3 +1,4 @@ +mod arena; mod ast; mod eval; pub mod inputsource; @@ -95,7 +96,7 @@ impl ProtocolDescription for ProtocolDescriptionImpl { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize)] pub struct ComponentStateImpl { prompt: Prompt, } diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index 80cf9765469db0064ad0f4d0f9d90f4268a2bdde..5fb8c4dfa236e3250a0bec7bf883888c283913c0 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -61,6 +61,9 @@ pub struct Configured { pub struct Connected { native_interface: Vec<(Port, Polarity)>, sync_batches: Vec, + // controller is cooperatively scheduled with the native application + // (except for transport layer behind Endpoints, which are managed by the OS) + // control flow is passed to the controller during methods on Connector (primarily, connect and sync). controller: Controller, } @@ -301,7 +304,8 @@ impl Default for Arena { impl Arena { pub fn alloc(&mut self, t: T) -> Port { self.storage.push(t); - Port::from_raw(self.storage.len() - 1) + let l: u32 = self.storage.len().try_into().unwrap(); + Port::from_raw(l - 1u32) } pub fn get(&self, key: Port) -> Option<&T> { self.storage.get(key.to_raw() as usize) @@ -319,7 +323,7 @@ impl Arena { self.storage.len() } pub fn keyspace(&self) -> impl Iterator { - (0..self.storage.len()).map(Port::from_raw) + (0u32..self.storage.len().try_into().unwrap()).map(Port::from_raw) } }