From 8d7a4ac5be3848c82df41166a6b9fe8acbfd5f9e Mon Sep 17 00:00:00 2001 From: Nadja Reitzenstein Date: Wed, 13 Oct 2021 04:57:40 +0200 Subject: [PATCH] the worst part of all of this is that it works :D --- src/bin/bffhd.rs | 3 + src/db/fix.rs | 7 +- src/db/hash.rs | 1 + src/db/mod.rs | 56 +++ src/db/resources.rs | 22 ++ src/db/state.rs | 261 ++++--------- src/db/typed.rs | 39 ++ src/{main.rs => lib.rs} | 36 +- src/network.rs | 89 +---- src/oid.rs | 837 ++++++++++++++++++++++++++++++++++++++++ src/resource.rs | 30 +- src/state/mod.rs | 115 ++++++ src/state/value.rs | 387 +++++++++++++++++++ 13 files changed, 1604 insertions(+), 279 deletions(-) create mode 100644 src/bin/bffhd.rs create mode 100644 src/db/resources.rs rename src/{main.rs => lib.rs} (85%) create mode 100644 src/oid.rs create mode 100644 src/state/mod.rs create mode 100644 src/state/value.rs diff --git a/src/bin/bffhd.rs b/src/bin/bffhd.rs new file mode 100644 index 0000000..10252a0 --- /dev/null +++ b/src/bin/bffhd.rs @@ -0,0 +1,3 @@ +fn main() { + diflouroborane::main() +} \ No newline at end of file diff --git a/src/db/fix.rs b/src/db/fix.rs index fd08c3c..ce5be19 100644 --- a/src/db/fix.rs +++ b/src/db/fix.rs @@ -22,7 +22,10 @@ pub struct LMDBorrow { impl<'env, T, V> LMDBorrow where T: Transaction, { - pub unsafe fn fix(txn: T, ptr: &'_ V) -> Self { + pub unsafe fn reborrow(ptr: &'_ V) -> NonNull { + ptr.into() + } + pub unsafe fn new(ptr: NonNull, txn: T) -> Self { Self { ptr: ptr.into(), txn, } } } @@ -37,5 +40,3 @@ impl<'env, T, V> Deref for LMDBorrow unsafe { self.ptr.as_ref() } } } - - diff --git a/src/db/hash.rs b/src/db/hash.rs index 962fda4..dbd2af7 100644 --- a/src/db/hash.rs +++ b/src/db/hash.rs @@ -38,6 +38,7 @@ pub struct Entry { pub val: V, } +#[derive(Clone, Copy)] pub struct HashAdapter { k: PhantomData, a: PhantomData, diff --git a/src/db/mod.rs b/src/db/mod.rs index 0c7fa33..f33d98d 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,3 +1,7 @@ +use std::{ + marker::PhantomData, +}; + pub use lmdb::{ Environment, @@ -10,6 +14,12 @@ pub use lmdb::{ RwTransaction, }; +use rkyv::{ + Fallible, + Serialize, + ser::serializers::AllocSerializer, +}; + mod raw; use raw::RawDB; @@ -33,6 +43,52 @@ pub use hash::{ mod fix; pub use fix::LMDBorrow; +pub mod state; +pub use state::{ + StateDB, +}; + +mod resources; +pub use resources::{ + ResourceDB, +}; + +pub enum DBError { + LMDB(lmdb::Error), + RKYV( as Fallible>::Error), +} + +impl From for DBError { + fn from(e: lmdb::Error) -> Self { + Self::LMDB(e) + } +} + +type Ser = AllocSerializer<1024>; +#[derive(Clone)] +struct AllocAdapter { + phantom: PhantomData, +} + +impl Fallible for AllocAdapter { + type Error = DBError; +} + +impl> Adapter for AllocAdapter { + type Serializer = Ser; + type Value = V; + + fn new_serializer() -> Self::Serializer { + Self::Serializer::default() + } + + fn from_ser_err(e: ::Error) -> Self::Error { + DBError::RKYV(e) + } + fn from_db_err(e: lmdb::Error) -> Self::Error { + e.into() + } +} #[cfg(test)] mod tests { diff --git a/src/db/resources.rs b/src/db/resources.rs new file mode 100644 index 0000000..31f1080 --- /dev/null +++ b/src/db/resources.rs @@ -0,0 +1,22 @@ +use rkyv::{ + Archive, + Serialize, + Deserialize, +}; + +use super::{ + AllocAdapter, + DB, +}; + +#[derive(Archive, Serialize, Deserialize)] +pub struct Resource { + uuid: u128, + id: String, + name_idx: u64, + description_idx: u64, +} + +pub struct ResourceDB { + db: DB>, +} diff --git a/src/db/state.rs b/src/db/state.rs index c78998f..3fbbe21 100644 --- a/src/db/state.rs +++ b/src/db/state.rs @@ -1,37 +1,11 @@ use std::{ - fmt, - - any::Any, - - collections::{ - hash_map::DefaultHasher - }, - hash::{ - Hash, - Hasher - }, - + sync::Arc, path::Path, }; -use rkyv::{ - Archive, - Archived, +use rkyv::Archived; - Serialize, - Deserialize, - - out_field, - - Fallible, - ser::serializers::AllocSerializer, -}; -use rkyv_dyn::{ - archive_dyn, -}; -use rkyv_typename::TypeName; - -use crate::db::{ +use super::{ DB, Environment, @@ -40,168 +14,25 @@ use crate::db::{ WriteFlags, Adapter, + AllocAdapter, + DBError, Transaction, + RoTransaction, RwTransaction, + + LMDBorrow, }; -#[archive_dyn(deserialize)] -/// Trait to be implemented by any value in the state map. -/// -/// A value can be any type not having dangling references (with the added restriction that it has -/// to implement `Debug` for debugger QoL). -/// In fact Value *also* needs to implement Hash since BFFH checks if the state is different to -/// before on input and output before updating the resource re. notifying actors and notifys. This -/// dependency is not expressable via supertraits since it is not possible to make Hash into a -/// trait object. -/// To solve this [`State`] uses the [`StateBuilder`] which adds an `Hash` requirement for inputs -/// on [`add`](struct::StateBuilder::add). The hash is being created over all inserted values and -/// then used to check for equality. Note that in addition to collisions, Hash is not guaranteed -/// stable over ordering and will additionally not track overwrites, so if the order of insertions -/// changes or values are set and later overwritten then two equal States can and are likely to -/// have different hashes. -pub trait Value: Any + fmt::Debug { } +use crate::state::State; -#[repr(transparent)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Archive, Serialize, Deserialize)] -#[archive_attr(derive(TypeName, Debug))] -pub struct Bool(bool); - -#[archive_dyn(deserialize)] -impl Value for Bool { } -impl Value for Archived { } - -#[repr(transparent)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Archive, Serialize, Deserialize)] -#[archive_attr(derive(TypeName, Debug))] -pub struct UInt32(u32); - -#[archive_dyn(deserialize)] -impl Value for UInt32 { } -impl Value for Archived { } - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Archive, Serialize, Deserialize)] -#[archive_attr(derive(TypeName, Debug))] -pub struct Vec3u8 { - a: u8, - b: u8, - c: u8, -} - -#[archive_dyn(deserialize)] -impl Value for Vec3u8 { } -impl Value for Archived { } - -#[derive(Archive, Serialize, Deserialize)] -/// State object of a resource -/// -/// This object serves three functions: -/// 1. it is constructed by modification via Claims or via internal resource logic -/// 2. it is serializable and storable in the database -/// 3. it is sendable and forwarded to all Actors and Notifys -pub struct State { - hash: u64, - inner: Vec<(String, Box)>, -} -impl PartialEq for State { - fn eq(&self, other: &Self) -> bool { - self.hash == other.hash - } -} -impl Eq for State {} - -impl fmt::Debug for State { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut sf = f.debug_struct("State"); - for (k, v) in self.inner.iter() { - sf.field(k, v); - } - sf.finish() - } -} - -impl State { - pub fn build() -> StateBuilder { - StateBuilder::new() - } - - pub fn hash(&self) -> u64 { - self.hash - } -} - -pub struct StateBuilder { - hasher: DefaultHasher, - inner: Vec<(String, Box)> -} - -impl StateBuilder { - pub fn new() -> Self { - let hasher = DefaultHasher::new(); - Self { inner: Vec::new(), hasher } - } - - pub fn finish(self) -> State { - State { - hash: self.hasher.finish(), - inner: self.inner, - } - } - - /// Add key-value pair to the State being built. - /// - /// We have to use this split system here because type erasure prevents us from limiting values - /// to `Hash`. Specifically, you can't have a trait object of `Hash` because `Hash` depends on - /// `Self`. In this function however the compiler still knows the exact type of `V` and can - /// call statically call its `hash` method. - pub fn add(mut self, key: String, val: V) -> Self - where V: SerializeValue + Hash - { - key.hash(&mut self.hasher); - val.hash(&mut self.hasher); - - self.inner.push((key, Box::new(val))); - - self - } -} - -struct StateAdapter; - -enum StateError { - LMDB(lmdb::Error), - RKYV( as Fallible>::Error), -} - -impl From for StateError { - fn from(e: lmdb::Error) -> Self { - Self::LMDB(e) - } -} - -impl Fallible for StateAdapter { - type Error = StateError; -} -impl Adapter for StateAdapter { - type Serializer = AllocSerializer<1024>; - type Value = State; - - fn new_serializer() -> Self::Serializer { - Self::Serializer::default() - } - - fn from_ser_err(e: ::Error) -> Self::Error { - StateError::RKYV(e) - } - fn from_db_err(e: lmdb::Error) -> Self::Error { - e.into() - } -} +type StateAdapter = AllocAdapter; /// State Database containing the currently set state +#[derive(Clone, Debug)] pub struct StateDB { /// The environment for all the databases below - env: Environment, + env: Arc, input: DB, output: DB, @@ -210,7 +41,7 @@ pub struct StateDB { } impl StateDB { - fn open_env>(path: &P) -> lmdb::Result { + fn open_env>(path: P) -> lmdb::Result { Environment::new() .set_flags( EnvironmentFlags::WRITE_MAP | EnvironmentFlags::NO_SUB_DIR @@ -221,10 +52,10 @@ impl StateDB { } fn new(env: Environment, input: DB, output: DB) -> Self { - Self { env, input, output } + Self { env: Arc::new(env), input, output } } - pub fn init>(path: &P) -> lmdb::Result { + pub fn init>(path: P) -> lmdb::Result { let env = Self::open_env(path)?; let input = unsafe { DB::create(&env, Some("input"), DatabaseFlags::INTEGER_KEY)? @@ -236,7 +67,7 @@ impl StateDB { Ok(Self::new(env, input, output)) } - pub fn open>(path: &P) -> lmdb::Result { + pub fn open>(path: P) -> lmdb::Result { let env = Self::open_env(path)?; let input = unsafe { DB::open(&env, Some("input"))? }; let output = unsafe { DB::open(&env, Some("output"))? }; @@ -245,7 +76,7 @@ impl StateDB { } fn update_txn(&self, txn: &mut RwTransaction, key: u64, input: &State, output: &State) - -> Result<(), ::Error> + -> Result<(), DBError> { let flags = WriteFlags::empty(); let k = key.to_ne_bytes(); @@ -254,14 +85,68 @@ impl StateDB { Ok(()) } - fn update(&self, key: u64, input: &State, output: &State) - -> Result<(), ::Error> + pub fn update(&self, key: u64, input: &State, output: &State) + -> Result<(), DBError> { let mut txn = self.env.begin_rw_txn().map_err(StateAdapter::from_db_err)?; self.update_txn(&mut txn, key, input, output)?; txn.commit().map_err(StateAdapter::from_db_err) } + + fn get(&self, db: &DB, key: u64) + -> Result>>, DBError> + { + let txn = self.env.begin_ro_txn().map_err(StateAdapter::from_db_err)?; + if let Some(state) = db.get(&txn, &key.to_ne_bytes())? { + let ptr = state.into(); + Ok(Some(unsafe { LMDBorrow::new(ptr, txn) })) + } else { + Ok(None) + } + } + + #[inline(always)] + pub fn get_input(&self, key: u64) + -> Result>>, DBError> + { self.get(&self.input, key) } + + #[inline(always)] + pub fn get_output(&self, key: u64) + -> Result>>, DBError> + { self.get(&self.output, key) } + + pub fn accessor(&self, key: u64) -> StateAccessor { + StateAccessor::new(key, self.clone()) + } +} + +#[derive(Debug)] +pub struct StateAccessor { + key: u64, + db: StateDB +} + +impl StateAccessor { + pub fn new(key: u64, db: StateDB) -> Self { + Self { key, db } + } + + pub fn get_input(&self) + -> Result>>, DBError> + { + self.db.get_input(self.key) + } + + pub fn get_output(&self) + -> Result>>, DBError> + { + self.db.get_output(self.key) + } + + pub fn set(&self, input: &State, output: &State) -> Result<(), DBError> { + self.db.update(self.key, input, output) + } } #[cfg(test)] diff --git a/src/db/typed.rs b/src/db/typed.rs index 08e99ff..7003424 100644 --- a/src/db/typed.rs +++ b/src/db/typed.rs @@ -1,4 +1,6 @@ use std::{ + fmt, + any::type_name, marker::PhantomData, }; @@ -39,6 +41,21 @@ pub trait Adapter: Fallible { fn from_db_err(e: lmdb::Error) -> ::Error; } +struct AdapterPrettyPrinter(PhantomData); + +impl AdapterPrettyPrinter { + pub fn new() -> Self { Self(PhantomData) } +} + +impl fmt::Debug for AdapterPrettyPrinter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(&type_name::()) + .field("serializer", &type_name::()) + .field("value", &type_name::()) + .finish() + } +} + pub trait OutputBuffer { type Buffer: AsRef<[u8]>; fn into_slice(self) -> Self::Buffer; @@ -59,6 +76,22 @@ pub struct DB { db: RawDB, phantom: PhantomData, } +impl Clone for DB { + fn clone(&self) -> Self { + Self { + db: self.db.clone(), + phantom: PhantomData, + } + } +} +impl fmt::Debug for DB { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DB") + .field("db", &self.db) + .field("adapter", &AdapterPrettyPrinter::::new()) + .finish() + } +} impl DB { fn new(db: RawDB) -> Self { @@ -167,6 +200,12 @@ impl<'txn, C, A> Cursor Self { cursor, phantom: PhantomData } } + pub fn iter_start(&mut self) -> Iter<'txn, A> { + let iter = self.cursor.iter_start(); + // Safe because `new` isn't :P + unsafe { Iter::new(iter) } + } + pub fn iter_dup_of>(&mut self, key: &K) -> Iter<'txn, A> { let iter = self.cursor.iter_dup_of(key); // Safe because `new` isn't :P diff --git a/src/main.rs b/src/lib.rs similarity index 85% rename from src/main.rs rename to src/lib.rs index 703cb9b..24dab81 100644 --- a/src/main.rs +++ b/src/lib.rs @@ -2,8 +2,6 @@ #![allow(dead_code)] #![forbid(unused_imports)] -extern crate async_trait; - /* mod modules; mod log; @@ -19,11 +17,16 @@ mod initiator; mod space; */ +use crate::oid::ObjectIdentifier; +use std::convert::TryFrom; +use crate::state::value::{UInt32, Vec3u8, SerializeValue}; + mod resource; mod schema; mod state; -mod error; mod db; +mod network; +mod oid; /* @@ -47,7 +50,32 @@ use crate::config::Config; */ pub fn main() { - + let db = db::StateDB::init("/tmp/state").unwrap(); + println!("{:#?}", db); + + let s = state::StateBuilder::new(); + let state = s.add( + ObjectIdentifier::try_from("1.3.6.1.4.1.48398.612.1").unwrap(), + Box::new(UInt32(0))) + .add( + ObjectIdentifier::try_from("1.3.6.1.4.1.48398.612.2").unwrap(), + Box::new(Vec3u8 { a: 1, b: 2, c: 3}) + ) + .finish(); + + println!("{:?}", state); + + let b = true; + println!("{:?}", b.archived_type_oid()); + + let boid = ObjectIdentifier::try_from("1.3.6.1.4.1.48398.612.1.1").unwrap(); + let b2 = Box::new(false); + let ent = state::value::Entry { oid: &boid, val: &b2 }; + println!("ent {:?}", &ent); + let s = serde_json::to_string(&ent).unwrap(); + println!("{}", &s); + let ent2: state::value::OwnedEntry = serde_json::from_str(&s).unwrap(); + println!("ent2: {:?}", ent2); } /*fn main() { diff --git a/src/network.rs b/src/network.rs index 68d9a40..51d1c02 100644 --- a/src/network.rs +++ b/src/network.rs @@ -1,82 +1,25 @@ -use std::fmt; +use std::{ + sync::Arc, + collections::HashMap, +}; -use std::sync::Mutex; -use std::collections::HashMap; +use futures_signals::signal::{ + Mutable, + MutableSignalCloned +}; -use futures::channel::mpsc; -use futures_signals::signal::Mutable; +use crate::state::State; -use crate::machine::Machine; -use crate::actor::ActorSignal; +type ResourceState = Mutable>; +type ResourceStateSignal = MutableSignalCloned>; -use crate::error::Result; - -pub type MachineMap = HashMap; -pub type ActorMap = HashMap>>>; -pub type InitMap = HashMap>>; - -#[derive(Debug, PartialEq, Eq)] -pub enum Error { - NoSuchInitiator(String), - NoSuchMachine(String), - NoSuchActor(String), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::NoSuchInitiator(n) => write!(f, "No initiator \"{}\" found.", n), - Error::NoSuchActor(n) => write!(f, "No actor \"{}\" found.", n), - Error::NoSuchMachine(n) => write!(f, "No machine \"{}\" found.", n), - } - } -} - -/// Main signal network +/// Connection Broker between Resources and Subscribers /// -/// Network as per FRP, not the one with packages and frames -// TODO De/Serialize established connection on startup/shutdown. +/// This serves as touch-off point between resources and anybody else. It doesn't drive +/// any state updates, it only allows subscribers to subscribe to the resources that are +/// driving the state updates pub struct Network { - inits: InitMap, - - // Store connections - //miconn: Vec<(String, String)>, - - pub machines: MachineMap, - - // Store connections - //maconn: Vec<(String, String)>, - - actors: ActorMap, + sources: HashMap, } -impl Network { - pub fn new(machines: MachineMap, actors: ActorMap, inits: InitMap) -> Self { - Self { machines, actors, inits } - } - pub fn connect_init(&self, init_key: &String, machine_key: &String) -> Result<()> { - let init = self.inits.get(init_key) - .ok_or_else(|| Error::NoSuchInitiator(init_key.clone()))?; - let machine = self.machines.get(machine_key) - .ok_or_else(|| Error::NoSuchMachine(machine_key.clone()))?; - - init.set(Some(machine.clone())); - Ok(()) - } - - pub fn connect_actor(&mut self, machine_key: &String, actor_key: &String) - -> Result<()> - { - let machine = self.machines.get(machine_key) - .ok_or_else(|| Error::NoSuchMachine(machine_key.clone()))?; - let actor = self.actors.get(actor_key) - .ok_or_else(|| Error::NoSuchActor(actor_key.clone()))?; - - // FIXME Yeah this should not unwrap. Really, really shoudln't. - let mut guard = actor.try_lock().unwrap(); - - guard.try_send(Some(Box::new(machine.signal()))) - .map_err(|_| Error::NoSuchActor(actor_key.clone()).into()) - } -} diff --git a/src/oid.rs b/src/oid.rs new file mode 100644 index 0000000..97d0a98 --- /dev/null +++ b/src/oid.rs @@ -0,0 +1,837 @@ +//! oid crate by https://github.com/UnnecessaryEngineering/oid turned into vendore'd module +//! +//! [Object Identifiers] are a standard of the [ITU] used to reference objects, things, and +//! concepts in a globally unique way. This crate provides for data structures and methods +//! to build, parse, and format OIDs. +//! +//! +//! ## Parsing OID String Representation +//! ```rust +//! use oid::prelude::*; +//! +//! fn main() -> Result<(), ObjectIdentifierError> { +//! let oid = ObjectIdentifier::try_from("0.1.2.3")?; +//! Ok(()) +//! } +//! ``` +//! +//! ## Parsing OID Binary Representation +//! ```rust +//! use oid::prelude::*; +//! +//! fn main() -> Result<(), ObjectIdentifierError> { +//! let oid = ObjectIdentifier::try_from(vec![0x00, 0x01, 0x02, 0x03])?; +//! Ok(()) +//! } +//! ``` +//! +//! ## Encoding OID as String Representation +//! ```rust +//! use oid::prelude::*; +//! +//! fn main() -> Result<(), ObjectIdentifierError> { +//! let oid = ObjectIdentifier::try_from("0.1.2.3")?; +//! let oid: String = oid.into(); +//! assert_eq!(oid, "0.1.2.3"); +//! Ok(()) +//! } +//! ``` +//! +//! ## Encoding OID as Binary Representation +//! ```rust +//! use oid::prelude::*; +//! +//! fn main() -> Result<(), ObjectIdentifierError> { +//! let oid = ObjectIdentifier::try_from(vec![0x00, 0x01, 0x02, 0x03])?; +//! let oid: Vec = oid.into(); +//! assert_eq!(oid, vec![0x00, 0x01, 0x02, 0x03]); +//! Ok(()) +//! } +//! ``` +//! +//! [Object Identifiers]: https://en.wikipedia.org/wiki/Object_identifier +//! [ITU]: https://en.wikipedia.org/wiki/International_Telecommunications_Union + +use core::convert::{TryFrom, TryInto}; + +use rkyv::{Archive, Serialize, Fallible}; +use rkyv::vec::{ArchivedVec, VecResolver}; + +// OID spec doesn't specify the maximum integer size of each node, so we default to usize +type Node = usize; + +/// Convenience module for quickly importing the public interface (e.g., `use oid::prelude::*`) +pub mod prelude { + pub use super::ObjectIdentifier; + pub use super::ObjectIdentifierRoot::*; + pub use super::ObjectIdentifierError; + pub use core::convert::{TryFrom, TryInto}; +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +#[repr(u8)] +pub enum ObjectIdentifierRoot { + ItuT = 0, + Iso = 1, + JointIsoItuT = 2, +} + +impl Into for ObjectIdentifierRoot { + fn into(self) -> String { + format!("{}", self as u8) + } +} + +impl TryFrom for ObjectIdentifierRoot { + type Error = ObjectIdentifierError; + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(ObjectIdentifierRoot::ItuT), + 1 => Ok(ObjectIdentifierRoot::Iso), + 2 => Ok(ObjectIdentifierRoot::JointIsoItuT), + _ => Err(ObjectIdentifierError::IllegalRootNode), + } + } +} + +/// Object Identifier Errors +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum ObjectIdentifierError { + /// Failed to parse OID due to illegal root node (must be 0-2 decimal) + IllegalRootNode, + /// Failed to parse OID due to illegal first node (must be 0-39 decimal) + IllegalFirstChildNode, + /// Failed to parse OID due to illegal child node value (except first node) + IllegalChildNodeValue, +} + +/// Object Identifier (OID) +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct ObjectIdentifier { + root: ObjectIdentifierRoot, + first_node: u8, + child_nodes: Vec, +} + +impl ObjectIdentifier { + const fn new(root: ObjectIdentifierRoot, first_node: u8, child_nodes: Vec) + -> Self + { + Self { root, first_node, child_nodes } + } +} + + +impl Archive for ObjectIdentifier { + type Archived = ArchivedVec; + type Resolver = VecResolver; + + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + let vec: Vec = self.clone().into(); + vec.resolve(pos, resolver, out); + } +} + +impl Serialize for ObjectIdentifier + where Vec: Serialize +{ + fn serialize(&self, serializer: &mut S) -> Result { + let vec: Vec = self.clone().into(); + vec.serialize(serializer) + } +} + +fn parse_string_first_node( + nodes: &mut dyn Iterator, +) -> Result { + if let Some(first_child_node) = nodes.next() { + let first_child_node: u8 = first_child_node + .parse() + .map_err(|_| ObjectIdentifierError::IllegalFirstChildNode)?; + if first_child_node > 39 { + return Err(ObjectIdentifierError::IllegalFirstChildNode); + } + Ok(first_child_node) + } else { + Err(ObjectIdentifierError::IllegalFirstChildNode) + } +} + +fn parse_string_child_nodes( + nodes: &mut dyn Iterator, +) -> Result, ObjectIdentifierError> { + let mut result: Vec = vec![]; + while let Some(node) = nodes.next() { + result.push( + node.parse() + .map_err(|_| ObjectIdentifierError::IllegalChildNodeValue)?, + ); + } + Ok(result) +} + +impl ObjectIdentifier { + fn from_string(value: S) -> Result + where + S: Into, + { + let value = value.into(); + let mut nodes = value.split("."); + match &nodes.next() { + Some(root_node_value) => { + let root_node_value: Result = root_node_value.parse(); + match root_node_value { + Ok(root_node) => { + let root_node: Result = root_node.try_into(); + match root_node { + Ok(root) => { + let first_node = parse_string_first_node(&mut nodes)?; + Ok(ObjectIdentifier { + root, + first_node, + child_nodes: parse_string_child_nodes(&mut nodes)?, + }) + } + Err(_err) => Err(ObjectIdentifierError::IllegalRootNode), + } + } + Err(_) => Err(ObjectIdentifierError::IllegalRootNode), + } + } + None => Err(ObjectIdentifierError::IllegalRootNode), + } + } +} + +impl Into for &ObjectIdentifier { + fn into(self) -> String { + let mut result: String = self.root.into(); + result.push_str(&format!(".{}", self.first_node)); + for node in &self.child_nodes { + result.push_str(&format!(".{}", node)); + } + result + } +} + +impl Into for ObjectIdentifier { + fn into(self) -> String { + (&self).into() + } +} + +impl Into> for &ObjectIdentifier { + fn into(self) -> Vec { + let mut result: Vec = vec![self.root as u8]; + result[0] = result[0] * 40 + self.first_node; + for node in self.child_nodes.iter() { + // TODO bench against !*node &= 0x80, compiler may already optimize better + if *node <= 127 { + result.push(*node as u8); + } else { + let mut value = *node; + let mut mask: Node = 0; + let mut encoded: Vec = vec![]; + while value > 0x80 { + encoded.insert(0, (value & 0x7f | mask) as u8); + value >>= 7; + mask = 0x80; + } + encoded.insert(0, (value | mask) as u8); + result.append(&mut encoded); + } + } + result + } +} + +impl Into> for ObjectIdentifier { + fn into(self) -> Vec { + (&self).into() + } +} + +impl TryFrom<&str> for ObjectIdentifier { + type Error = ObjectIdentifierError; + fn try_from(value: &str) -> Result { + ObjectIdentifier::from_string(value) + } +} + +impl TryFrom for ObjectIdentifier { + type Error = ObjectIdentifierError; + fn try_from(value: String) -> Result { + ObjectIdentifier::from_string(value) + } +} + +impl TryFrom<&[u8]> for ObjectIdentifier { + type Error = ObjectIdentifierError; + fn try_from(value: &[u8]) -> Result { + if value.len() < 1 { + return Err(ObjectIdentifierError::IllegalRootNode); + }; + let root = ObjectIdentifierRoot::try_from(value[0] / 40)?; + let first_node = value[0] % 40; + let mut child_nodes = vec![]; + let mut parsing_big_int = false; + let mut big_int: Node = 0; + for i in 1..value.len() { + if !parsing_big_int && value[i] < 128 { + child_nodes.push(value[i] as Node); + } else { + if big_int > 0 { + if big_int >= Node::max_value() >> 7 { + return Err(ObjectIdentifierError::IllegalChildNodeValue); + } + big_int <<= 7; + }; + big_int |= (value[i] & !0x80) as Node; + parsing_big_int = value[i] & 0x80 != 0; + } + if big_int > 0 && !parsing_big_int { + child_nodes.push(big_int); + big_int = 0; + } + } + Ok(ObjectIdentifier { + root, + first_node, + child_nodes, + }) + } +} + +impl TryFrom> for ObjectIdentifier { + type Error = ObjectIdentifierError; + fn try_from(value: Vec) -> Result { + value.as_slice().try_into() + } +} + +mod serde_support { + use super::*; + use core::fmt; + use serde::{de, ser}; + + struct OidVisitor; + + impl<'de> de::Visitor<'de> for OidVisitor { + type Value = ObjectIdentifier; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a valid buffer representing an OID") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: de::Error, + { + ObjectIdentifier::try_from(v).map_err(|err| { + E::invalid_value( + de::Unexpected::Other(match err { + ObjectIdentifierError::IllegalRootNode => "illegal root node", + ObjectIdentifierError::IllegalFirstChildNode => "illegal first child node", + ObjectIdentifierError::IllegalChildNodeValue => "illegal child node value", + }), + &"a valid buffer representing an OID", + ) + }) + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + ObjectIdentifier::try_from(v).map_err(|err| { + E::invalid_value( + de::Unexpected::Other(match err { + ObjectIdentifierError::IllegalRootNode => "illegal root node", + ObjectIdentifierError::IllegalFirstChildNode => "illegal first child node", + ObjectIdentifierError::IllegalChildNodeValue => "illegal child node value", + }), + &"a string representing an OID", + ) + }) + } + } + + impl<'de> de::Deserialize<'de> for ObjectIdentifier { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + if deserializer.is_human_readable() { + deserializer.deserialize_str(OidVisitor) + } else { + deserializer.deserialize_bytes(OidVisitor) + } + } + } + + impl ser::Serialize for ObjectIdentifier { + fn serialize( + &self, + serializer: S, + ) -> Result<::Ok, ::Error> + where + S: ser::Serializer, + { + if serializer.is_human_readable() { + let encoded: String = self.into(); + serializer.serialize_str(&encoded) + } else { + let encoded: Vec = self.into(); + serializer.serialize_bytes(&encoded) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + mod serde_support { + use super::*; + use serde_derive::{Deserialize, Serialize}; + use serde_xml_rs; + + #[test] + fn bincode_serde_serialize() { + let expected: Vec = vec![ + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, + 0x0D, 0x15, + ]; + let oid = ObjectIdentifier { + root: ObjectIdentifierRoot::ItuT, + first_node: 0x01, + child_nodes: vec![1, 2, 3, 5, 8, 13, 21], + }; + let actual: Vec = bincode::serialize(&oid).unwrap(); + assert_eq!(expected, actual); + } + + #[test] + fn bincode_serde_deserialize() { + let expected = ObjectIdentifier { + root: ObjectIdentifierRoot::ItuT, + first_node: 0x01, + child_nodes: vec![1, 2, 3, 5, 8, 13, 21], + }; + let actual: ObjectIdentifier = bincode::deserialize(&[ + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, + 0x0D, 0x15, + ]) + .unwrap(); + assert_eq!(expected, actual); + } + + #[derive(Debug, Deserialize, PartialEq, Serialize)] + struct MyStruct { + oid: ObjectIdentifier + } + + #[test] + fn xml_serde_serialize() { + let mydata = MyStruct { + oid: ObjectIdentifier::try_from("1.2.3.5.8.13.21").unwrap() + }; + let expected = r#"1.2.3.5.8.13.21"#; + let actual = serde_xml_rs::to_string(&mydata).unwrap(); + assert_eq!(expected, actual); + } + + #[test] + fn xml_serde_deserialize_element() { + let src = r#"1.2.3.5.8.13.21"#; + + let expected = MyStruct { + oid: ObjectIdentifier::try_from("1.2.3.5.8.13.21").unwrap() + }; + let actual: MyStruct = serde_xml_rs::from_str(&src).unwrap(); + assert_eq!(expected, actual); + } + + #[test] + fn xml_serde_deserialize_attribute() { + let src = r#""#; + + let expected = MyStruct { + oid: ObjectIdentifier::try_from("1.2.3.5.8.13.21").unwrap() + }; + let actual: MyStruct = serde_xml_rs::from_str(&src).unwrap(); + assert_eq!(expected, actual); + } + } + + #[test] + fn encode_binary_root_node_0() { + let expected: Vec = vec![0]; + let oid = ObjectIdentifier { + root: ObjectIdentifierRoot::ItuT, + first_node: 0x00, + child_nodes: vec![], + }; + let actual: Vec = (&oid).into(); + assert_eq!(expected, actual); + } + + #[test] + fn encode_binary_root_node_1() { + let expected: Vec = vec![40]; + let oid = ObjectIdentifier { + root: ObjectIdentifierRoot::Iso, + first_node: 0x00, + child_nodes: vec![], + }; + let actual: Vec = (&oid).into(); + assert_eq!(expected, actual); + } + + #[test] + fn encode_binary_root_node_2() { + let expected: Vec = vec![80]; + let oid = ObjectIdentifier { + root: ObjectIdentifierRoot::JointIsoItuT, + first_node: 0x00, + child_nodes: vec![], + }; + let actual: Vec = (&oid).into(); + assert_eq!(expected, actual); + } + + #[test] + fn encode_binary_example_1() { + let expected: Vec = vec![0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0D, 0x15]; + let oid = ObjectIdentifier { + root: ObjectIdentifierRoot::ItuT, + first_node: 0x01, + child_nodes: vec![1, 2, 3, 5, 8, 13, 21], + }; + let actual: Vec = (&oid).into(); + assert_eq!(expected, actual); + } + + #[test] + fn encode_binary_example_2() { + let expected: Vec = vec![ + 0x77, 0x2A, 0x93, 0x45, 0x83, 0xFF, 0x7F, 0x87, 0xFF, 0xFF, 0xFF, 0x7F, 0x89, 0x53, + 0x92, 0x30, + ]; + let oid = ObjectIdentifier { + root: ObjectIdentifierRoot::JointIsoItuT, + first_node: 39, + child_nodes: vec![42, 2501, 65535, 2147483647, 1235, 2352], + }; + let actual: Vec = (&oid).into(); + assert_eq!(expected, actual); + } + + #[test] + fn encode_string_root_node_0() { + let expected = "0.0"; + let oid = ObjectIdentifier { + root: ObjectIdentifierRoot::ItuT, + first_node: 0x00, + child_nodes: vec![], + }; + let actual: String = (&oid).into(); + assert_eq!(expected, actual); + } + + #[test] + fn encode_string_root_node_1() { + let expected = "1.0"; + let oid = ObjectIdentifier { + root: ObjectIdentifierRoot::Iso, + first_node: 0x00, + child_nodes: vec![], + }; + let actual: String = (&oid).into(); + assert_eq!(expected, actual); + } + + #[test] + fn encode_string_root_node_2() { + let expected = "2.0"; + let oid = ObjectIdentifier { + root: ObjectIdentifierRoot::JointIsoItuT, + first_node: 0x00, + child_nodes: vec![], + }; + let actual: String = (&oid).into(); + assert_eq!(expected, actual); + } + + #[test] + fn encode_string_example_1() { + let expected = "0.1.1.2.3.5.8.13.21"; + let oid = ObjectIdentifier { + root: ObjectIdentifierRoot::ItuT, + first_node: 0x01, + child_nodes: vec![1, 2, 3, 5, 8, 13, 21], + }; + let actual: String = (&oid).into(); + assert_eq!(expected, actual); + } + + #[test] + fn encode_string_example_2() { + let expected = "2.39.42.2501.65535.2147483647.1235.2352"; + let oid = ObjectIdentifier { + root: ObjectIdentifierRoot::JointIsoItuT, + first_node: 39, + child_nodes: vec![42, 2501, 65535, 2147483647, 1235, 2352], + }; + let actual: String = (&oid).into(); + assert_eq!(expected, actual); + } + + #[test] + fn parse_binary_root_node_0() { + let expected = Ok(ObjectIdentifier { + root: ObjectIdentifierRoot::ItuT, + first_node: 0x00, + child_nodes: vec![], + }); + let actual = vec![0x00].try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn parse_binary_root_node_1() { + let expected = Ok(ObjectIdentifier { + root: ObjectIdentifierRoot::Iso, + first_node: 0x00, + child_nodes: vec![], + }); + let actual = vec![40].try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn parse_binary_root_node_2() { + let expected = Ok(ObjectIdentifier { + root: ObjectIdentifierRoot::JointIsoItuT, + first_node: 0x00, + child_nodes: vec![], + }); + let actual = vec![80].try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn parse_binary_example_1() { + let expected = Ok(ObjectIdentifier { + root: ObjectIdentifierRoot::ItuT, + first_node: 0x01, + child_nodes: vec![1, 2, 3, 5, 8, 13, 21], + }); + let actual = vec![0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0D, 0x15].try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn parse_binary_example_2() { + let expected = Ok(ObjectIdentifier { + root: ObjectIdentifierRoot::JointIsoItuT, + first_node: 39, + child_nodes: vec![42, 2501, 65535, 2147483647, 1235, 2352], + }); + let actual = vec![ + 0x77, 0x2A, 0x93, 0x45, 0x83, 0xFF, 0x7F, 0x87, 0xFF, 0xFF, 0xFF, 0x7F, 0x89, 0x53, + 0x92, 0x30, + ] + .try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn parse_string_root_node_0() { + let expected = Ok(ObjectIdentifier { + root: ObjectIdentifierRoot::ItuT, + first_node: 0x00, + child_nodes: vec![], + }); + let actual = "0.0".try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn parse_string_root_node_1() { + let expected = Ok(ObjectIdentifier { + root: ObjectIdentifierRoot::Iso, + first_node: 0x00, + child_nodes: vec![], + }); + let actual = "1.0".try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn parse_string_root_node_2() { + let expected = Ok(ObjectIdentifier { + root: ObjectIdentifierRoot::JointIsoItuT, + first_node: 0x00, + child_nodes: vec![], + }); + let actual = "2.0".try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn parse_string_example_1() { + let expected = Ok(ObjectIdentifier { + root: ObjectIdentifierRoot::ItuT, + first_node: 0x01, + child_nodes: vec![1, 2, 3, 5, 8, 13, 21], + }); + let actual = "0.1.1.2.3.5.8.13.21".try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn parse_string_example_2() { + let expected = Ok(ObjectIdentifier { + root: ObjectIdentifierRoot::JointIsoItuT, + first_node: 39, + child_nodes: vec![42, 2501, 65535, 2147483647, 1235, 2352], + }); + let actual = "2.39.42.2501.65535.2147483647.1235.2352".try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn illegal_oid_root() { + let expected = Err(ObjectIdentifierError::IllegalRootNode); + for i in 3..core::u8::MAX { + let actual = ObjectIdentifierRoot::try_from(i); + assert_eq!(expected, actual); + } + } + + #[test] + fn illegal_first_node_too_large() { + let expected = Err(ObjectIdentifierError::IllegalFirstChildNode); + for i in 40..core::u8::MAX { + let string_val = format!("{}.2.3.4", i); + let mut nodes_iter = string_val.split("."); + let actual = parse_string_first_node(&mut nodes_iter); + assert_eq!(expected, actual); + } + } + + #[test] + fn illegal_first_node_empty() { + let expected = Err(ObjectIdentifierError::IllegalFirstChildNode); + let string_val = String::new(); + let mut nodes_iter = string_val.split("."); + let actual = parse_string_first_node(&mut nodes_iter); + assert_eq!(expected, actual); + } + + #[test] + fn illegal_first_node_none() { + let expected = Err(ObjectIdentifierError::IllegalFirstChildNode); + let string_val = String::new(); + let mut nodes_iter = string_val.split("."); + let _ = nodes_iter.next(); + let actual = parse_string_first_node(&mut nodes_iter); + assert_eq!(expected, actual); + } + + #[test] + fn illegal_first_node_large() { + let expected = Err(ObjectIdentifierError::IllegalFirstChildNode); + let string_val = String::from("40"); + let mut nodes_iter = string_val.split("."); + let actual = parse_string_first_node(&mut nodes_iter); + assert_eq!(expected, actual); + } + + #[test] + fn parse_string_crap() { + let expected: Result = + Err(ObjectIdentifierError::IllegalRootNode); + let actual = "wtf".try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn parse_string_empty() { + let expected: Result = + Err(ObjectIdentifierError::IllegalRootNode); + let actual = String::new().try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn parse_binary_empty() { + let expected: Result = + Err(ObjectIdentifierError::IllegalRootNode); + let actual = vec![].try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn parse_binary_example_over_u128() { + let expected: Result = + Err(ObjectIdentifierError::IllegalChildNodeValue); + let actual = vec![ + 0x00, 0x89, 0x97, 0xBF, 0xA3, 0xB8, 0xE8, 0xB3, 0xE6, 0xFB, 0xF2, 0xEA, 0xC3, 0xCA, + 0xF2, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, + ] + .try_into(); + assert_eq!(expected, actual); + } + #[test] + fn parse_string_root_node_3plus() { + for i in 3..=core::u8::MAX { + let expected: Result = + Err(ObjectIdentifierError::IllegalRootNode); + let actual = format!("{}", i).try_into(); + assert_eq!(expected, actual); + } + } + + #[test] + fn parse_string_example_over_u128() { + let expected: Result = + Err(ObjectIdentifierError::IllegalChildNodeValue); + let actual = "1.1.349239782398732987223423423423423423423423423423434982342342342342342342324523453452345234523452345234523452345234537234987234".try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn parse_string_example_first_node_over_39() { + let expected: Result = + Err(ObjectIdentifierError::IllegalFirstChildNode); + let actual = "1.40.1.2.3".try_into(); + assert_eq!(expected, actual); + } + + #[test] + fn encode_to_string() { + let expected = String::from("1.2.3.4"); + let actual: String = ObjectIdentifier { + root: ObjectIdentifierRoot::Iso, + first_node: 2, + child_nodes: vec![3, 4], + } + .into(); + assert_eq!(expected, actual); + } + + #[test] + fn encode_to_bytes() { + let expected = vec![0x2A, 0x03, 0x04]; + let actual: Vec = ObjectIdentifier { + root: ObjectIdentifierRoot::Iso, + first_node: 2, + child_nodes: vec![3, 4], + } + .into(); + assert_eq!(expected, actual); + } +} diff --git a/src/resource.rs b/src/resource.rs index d35ceb3..8ebaf32 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -5,8 +5,11 @@ use futures_signals::signal::Mutable; use smol::channel::Receiver; -use crate::error::Error; -use crate::state::{State, StateDB}; +use crate::state::State; +use crate::db::{ + state::StateAccessor, + DBError, +}; /// A resource in BFFH has to contain several different parts; /// - Currently set state @@ -37,24 +40,26 @@ use crate::state::{State, StateDB}; /// - Check authorization of updates i.e. is this user allowed to do that #[async_trait] pub trait Resource { - /// Returns true if the given state is valid, and false otherwise - fn validate(&mut self, state: &State) -> bool; - /// Run whatever internal logic this resource has for the given State update, and return the /// new output state that this update produces. - async fn update(&mut self, state: &State) -> Result; + async fn update(&mut self, input: &State /*, internal: &State*/) -> Result; } pub struct Update { pub state: State, - pub errchan: oneshot::Sender, + pub errchan: oneshot::Sender, } pub struct ResourceDriver { + // putput res: Box, - db: StateDB, + // input rx: Receiver, + + // output + db: StateAccessor, + signal: Mutable, } @@ -72,11 +77,14 @@ impl ResourceDriver { // Not applying the new state isn't correct either since we don't know what the // internal logic of the resource has done to make this happen. // Another half right solution is to unwrap and recreate everything. - //self.db.store(&state, &outstate); - self.signal.set_neq(outstate); + // "Best" solution would be to tell the resource to rollback their interal + // changes on a fatal failure and then notify the Claimant, while simply trying + // again for temporary failures. + let _ = self.db.set(&state, &outstate); + self.signal.set(outstate); }, Err(e) => { - errchan.send(e); + let _ = errchan.send(e); } } } diff --git a/src/state/mod.rs b/src/state/mod.rs new file mode 100644 index 0000000..65a1ee7 --- /dev/null +++ b/src/state/mod.rs @@ -0,0 +1,115 @@ +use std::{ + fmt, + + collections::{ + hash_map::DefaultHasher + }, + hash::{ + Hash, + Hasher + }, +}; + +use rkyv::{ + Archive, + Archived, + + Serialize, + Deserialize, + + out_field, +}; + +use crate::oid::ObjectIdentifier; + +pub mod value; +pub use value::{ + SerializeDynValue, + DeserializeDynValue, +}; + +#[derive(Archive, Serialize, Deserialize)] +pub struct StateEntry { + key: ObjectIdentifier, + val: Box, +} + +#[derive(Archive, Serialize, Deserialize)] +/// State object of a resource +/// +/// This object serves three functions: +/// 1. it is constructed by modification via Claims or via internal resource logic +/// 2. it is serializable and storable in the database +/// 3. it is sendable and forwarded to all Actors and Notifys +pub struct State { + hash: u64, + inner: Vec, +} +impl PartialEq for State { + fn eq(&self, other: &Self) -> bool { + self.hash == other.hash + } +} +impl PartialEq> for State { + fn eq(&self, other: &Archived) -> bool { + self.hash == other.hash + } +} +impl Eq for State {} + +impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut sf = f.debug_struct("State"); + for StateEntry { key, val } in self.inner.iter() { + let k: String = key.into(); + sf.field(k.as_ref(), val); + } + sf.finish() + } +} + +impl State { + pub fn build() -> StateBuilder { + StateBuilder::new() + } + + pub fn hash(&self) -> u64 { + self.hash + } +} + +pub struct StateBuilder { + hasher: DefaultHasher, + inner: Vec +} + +impl StateBuilder { + pub fn new() -> Self { + let hasher = DefaultHasher::new(); + Self { inner: Vec::new(), hasher } + } + + pub fn finish(self) -> State { + State { + hash: self.hasher.finish(), + inner: self.inner, + } + } + + /// Add key-value pair to the State being built. + /// + /// We have to use this split system here because type erasure prevents us from limiting values + /// to `Hash`. Specifically, you can't have a trait object of `Hash` because `Hash` depends on + /// `Self`. In this function however the compiler still knows the exact type of `V` and can + /// call statically call its `hash` method. + pub fn add(mut self, key: ObjectIdentifier<>, val: Box) -> Self + where V: SerializeDynValue + Hash + { + // Hash before creating the StateEntry struct which removes the type information + key.hash(&mut self.hasher); + val.hash(&mut self.hasher); + self.inner.push(StateEntry { key, val }); + + self + } +} \ No newline at end of file diff --git a/src/state/value.rs b/src/state/value.rs new file mode 100644 index 0000000..3390904 --- /dev/null +++ b/src/state/value.rs @@ -0,0 +1,387 @@ +use core::{ + ptr, +}; +use std::{ + fmt, + any::Any, + hash::Hash, + ops::Deref, + convert::TryFrom, +}; + +use rkyv::{Archive, Archived, Serialize, Deserialize, out_field, }; +use rkyv_dyn::{archive_dyn, DynSerializer, DynError, DynDeserializer}; +use rkyv_typename::TypeName; +use ptr_meta::{DynMetadata, Pointee}; +use std::marker::PhantomData; + +use inventory; +use crate::oid::{ObjectIdentifier}; +use rkyv::ser::{Serializer, }; +use std::collections::HashMap; +use std::alloc::Layout; +use serde::ser::SerializeMap; +use std::fmt::Formatter; +use serde::de::Error as _; + + +pub trait Value: fmt::Debug + erased_serde::Serialize { + fn deserialize_val_in_place<'de>(&mut self, deserializer: &mut dyn erased_serde::Deserializer<'de>) + -> Result<(), erased_serde::Error>; +} +erased_serde::serialize_trait_object!(Value); + +impl Value for T + where T: fmt::Debug + Archive + erased_serde::Serialize + for<'de> serde::Deserialize<'de> +{ + fn deserialize_val_in_place<'de>(&mut self, deserializer: &mut dyn erased_serde::Deserializer<'de>) + -> Result<(), erased_serde::Error> + { + *self = erased_serde::deserialize(deserializer)?; + Ok(()) + } +} + +impl Pointee for dyn Value { + type Metadata = DynMetadata; +} + +#[derive(Debug)] +pub struct Entry<'a> { + pub oid: &'a ObjectIdentifier, + pub val: &'a dyn Value, +} +#[derive(Debug)] +pub struct OwnedEntry { + pub oid: ObjectIdentifier, + pub val: Box, +} + +impl<'a> serde::Serialize for Entry<'a> { + fn serialize(&self, serializer: S) -> Result + where S: serde::Serializer + { + let mut ser = serializer.serialize_map(Some(1))?; + ser.serialize_entry(self.oid, self.val)?; + ser.end() + } +} + +impl<'de> serde::Deserialize<'de> for OwnedEntry { + fn deserialize(deserializer: D) -> Result + where D: serde::Deserializer<'de> + { + deserializer.deserialize_map(OwnedEntryVisitor) + } +} +struct OwnedEntryVisitor; +impl<'de> serde::de::Visitor<'de> for OwnedEntryVisitor { + type Value = OwnedEntry; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + write!(formatter, "an one entry map from OID to some value object") + } + + fn visit_map>(self, mut map: A) -> Result + { + // Bad magic code. Problem we have to solve: We only know how to parse whatever comes + // after the OID after having looked at the OID. We have zero static type info available + // during deserialization. Soooooo: + + // Get OID first. That's easy, we know it's the key, we know how to read it. + let oid: ObjectIdentifier = map.next_key()? + .ok_or(A::Error::missing_field("oid"))?; + let b: Vec = oid.clone().into(); + + // Get the Value vtable for that OID. Or fail because we don't know that OID, either works. + let valimpl = IMPL_REGISTRY.get(ImplId::from_type_oid(&b)) + .ok_or(serde::de::Error::invalid_value( + serde::de::Unexpected::Other("unknown oid"), + &"oid an implementation was registered for" + ))?; + + // Casting random usize you find on the side of the road as vtable on unchecked pointers. + // What could possibly go wrong? >:D + let valbox: Box = unsafe { + // recreate vtable as fat ptr metadata + let meta = valimpl.pointer_metadata(); + + // Don't bother checking here. The only way this could be bad is if the vtable above + // is bad an in that case a segfault here would be *much better* than whatever is + // going to happen afterwards. + let layout = Layout::from_size_align_unchecked(meta.size_of(), meta.align_of()); + + // Hello yes I would like a Box the old fashioned way. + // Oh you're asking why we're allocating stuff here and never ever bother zeroing or + // validate in any other way if this is sane? + // Well... + let ptr: *mut () = std::alloc::alloc(layout).cast::<()>(); + Box::from_raw(ptr_meta::from_raw_parts_mut(ptr, meta)) + }; + // ... The only way we can make Value a trait object by having it deserialize *into + // it's own uninitialized representation*. Yeah don't worry, this isn't the worst part of + // the game yet. >:D + let seed = ValueSeed(valbox); + let val = map.next_value_seed(seed)?; + Ok(OwnedEntry { oid, val }) + } +} +struct ValueSeed(Box); +impl<'de> serde::de::DeserializeSeed<'de> for ValueSeed { + type Value = Box; + + fn deserialize(mut self, deserializer: D) -> Result + where D: serde::Deserializer<'de> + { + let mut deser = ::erase(deserializer); + // Hey, better initialize late than never. Oh completely unrelated but if we unwind after + // allocating the box and before completing this function call that's undefined behaviour + // so maybe don't do that thanks <3 + self.0.deserialize_val_in_place(&mut deser); + Ok(self.0) + } +} + +pub trait TypeOid { + fn get_type_oid() -> ObjectIdentifier; +} + +impl TypeOid for Archived { + fn get_type_oid() -> ObjectIdentifier { + ObjectIdentifier::try_from("1.3.6.1.4.1.48398.612.1.1").unwrap() + } +} + +pub trait SerializeValue { + fn serialize_val(&self, serializer: &mut dyn DynSerializer) -> Result; + fn archived_type_oid(&self) -> ObjectIdentifier; +} + +impl SerializeValue for T + where T: for<'a> Serialize, + T::Archived: TypeOid, +{ + fn serialize_val(&self, serializer: &mut dyn DynSerializer) -> Result { + serializer.serialize_value(self) + } + + fn archived_type_oid(&self) -> ObjectIdentifier { + Archived::::get_type_oid() + } +} + +trait DeserializeValue { + unsafe fn deserialize_val( + &self, + deserializer: &mut dyn DynDeserializer, + alloc: &mut dyn FnMut(Layout) -> *mut u8, + ) -> Result<*mut (), DynError>; + + fn deserialize_dyn_metadata( + &self, + deserializer: &mut dyn DynDeserializer, + ) -> Result; +} + +pub struct ArchivedValueMetadata { + type_oid: Archived, + phantom: PhantomData, +} + +impl ArchivedValueMetadata { + pub unsafe fn emplace(type_oid: Archived, out: *mut Self) { + ptr::addr_of_mut!((*out).type_oid).write(type_oid); + } + + pub fn vtable(&self) -> usize { + IMPL_REGISTRY + .get(ImplId::from_type_oid(&self.type_oid)) + .expect("Unregistered type oid") + .vtable + } + + pub fn pointer_metadata(&self) -> DynMetadata { + unsafe { core::mem::transmute(self.vtable()) } + } +} + +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +struct ImplId<'a> { + type_oid: &'a [u8], +} + +impl<'a> ImplId<'a> { + fn from_type_oid(type_oid: &'a [u8]) -> Self { + Self { type_oid } + } +} +impl ImplId<'static> { + fn new() -> Self { + let oid: Vec = T::get_type_oid().into(); + Self { + type_oid: oid.leak() + } + } +} + +#[derive(Copy, Clone, Debug)] +struct ImplData { + pub vtable: usize, + // TODO DebugImpl + // TODO DebugInfo +} +impl ImplData { + pub unsafe fn pointer_metadata(&self) -> DynMetadata { + core::mem::transmute(self.vtable) + } +} + +struct ImplEntry<'a> { + id: ImplId<'a>, + data: ImplData, +} +inventory::collect!(ImplEntry<'static>); + +impl ImplEntry<'_> { + #[doc(hidden)] + pub fn new() -> Self { + Self { + id: ImplId::new::(), + data: ImplData { + vtable: ::vtable(), + }, + } + } +} + +struct ImplRegistry { + oid_to_data: HashMap, ImplData>, +} + +impl ImplRegistry { + fn new() -> Self { + Self { oid_to_data: HashMap::new() } + } + + fn add_entry(&mut self, entry: &'static ImplEntry) { + let old_val = self.oid_to_data.insert(entry.id, entry.data); + assert!(old_val.is_none()); + } + + fn get(&self, type_oid: ImplId) -> Option { + self.oid_to_data.get(&type_oid).map(|d| *d) + } +} + +lazy_static::lazy_static! { + // FIXME: Dynamic modules *will* break this. + static ref IMPL_REGISTRY: ImplRegistry = { + let mut reg = ImplRegistry::new(); + for entry in inventory::iter:: { + reg.add_entry(entry); + } + reg + }; +} + +pub unsafe trait RegisteredImpl { + fn vtable() -> usize; +} + +unsafe impl RegisteredImpl for bool { + fn vtable() -> usize { + unsafe { + core::mem::transmute(ptr_meta::metadata( + core::ptr::null::() as *const dyn Value + )) + } + } +} +inventory::submit! {ImplEntry::new::()} + +#[archive_dyn(deserialize)] +/// Trait to be implemented by any value in the state map. +/// +/// A value can be any type not having dangling references (with the added +/// restriction that it has to implement `Debug` for debugger QoL). +/// In fact Value *also* needs to implement Hash since BFFH checks if the state +/// is different to before on input and output before updating the resource re. +/// notifying actors and notifys. This dependency is not expressable via +/// supertraits since it is not possible to make Hash into a trait object. +/// To solve this [`State`] uses the [`StateBuilder`] which adds an `Hash` +/// requirement for inputs on [`add`](struct::StateBuilder::add). The hash is +/// being created over all inserted values and then used to check for equality. +/// Note that in addition to collisions, Hash is not guaranteed stable over +/// ordering and will additionally not track overwrites, so if the order of +/// insertions changes or values are set and later overwritten then two equal +/// States can and are likely to have different hashes. +pub trait DynValue: Any + fmt::Debug {} + +macro_rules! valtype { + ( $x:ident, $y:ident ) => { + #[repr(transparent)] + #[derive(Debug, PartialEq, Eq, Hash)] + #[derive(Archive, Serialize, Deserialize)] + #[derive(serde::Serialize, serde::Deserialize)] + #[archive_attr(derive(TypeName, Debug))] + pub struct $x(pub $y); + + #[archive_dyn(deserialize)] + impl DynValue for $x {} + impl DynValue for Archived<$x> {} + + impl Deref for $x { + type Target = $y; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl From<$y> for $x { + fn from(e: $y) -> $x { + Self(e) + } + } + + impl $x { + pub fn new(e: $y) -> Self { + Self(e) + } + + pub fn into_inner(self) -> $y { + self.0 + } + } + } +} + +valtype!(Bool, bool); +valtype!(UInt8, u8); +valtype!(UInt16, u16); +valtype!(UInt32, u32); +valtype!(UInt64, u64); +valtype!(UInt128, u128); +valtype!(Int8, i8); +valtype!(Int16, i16); +valtype!(Int32, i32); +valtype!(Int64, i64); +valtype!(Int128, i128); +valtype!(RString, String); + +#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Archive, Serialize, Deserialize)] +#[archive_attr(derive(TypeName, Debug))] +pub struct Vec3u8 { + pub a: u8, + pub b: u8, + pub c: u8, +} + +#[archive_dyn(deserialize)] +impl DynValue for Vec3u8 {} + +impl DynValue for Archived {} + +#[cfg(test)] +mod tests { +} \ No newline at end of file