the worst part of all of this is that it works :D

This commit is contained in:
Nadja Reitzenstein 2021-10-13 04:57:40 +02:00
parent 33131f38c4
commit 8d7a4ac5be
13 changed files with 1604 additions and 279 deletions

3
src/bin/bffhd.rs Normal file
View File

@ -0,0 +1,3 @@
fn main() {
diflouroborane::main()
}

View File

@ -22,7 +22,10 @@ pub struct LMDBorrow<T, V> {
impl<'env, T, V> LMDBorrow<T, V>
where T: Transaction,
{
pub unsafe fn fix(txn: T, ptr: &'_ V) -> Self {
pub unsafe fn reborrow(ptr: &'_ V) -> NonNull<V> {
ptr.into()
}
pub unsafe fn new(ptr: NonNull<V>, txn: T) -> Self {
Self { ptr: ptr.into(), txn, }
}
}
@ -37,5 +40,3 @@ impl<'env, T, V> Deref for LMDBorrow<T, V>
unsafe { self.ptr.as_ref() }
}
}

View File

@ -38,6 +38,7 @@ pub struct Entry<K: Archive, V: Archive> {
pub val: V,
}
#[derive(Clone, Copy)]
pub struct HashAdapter<K, A> {
k: PhantomData<K>,
a: PhantomData<A>,

View File

@ -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(<AllocSerializer<1024> as Fallible>::Error),
}
impl From<lmdb::Error> for DBError {
fn from(e: lmdb::Error) -> Self {
Self::LMDB(e)
}
}
type Ser = AllocSerializer<1024>;
#[derive(Clone)]
struct AllocAdapter<V> {
phantom: PhantomData<V>,
}
impl<V> Fallible for AllocAdapter<V> {
type Error = DBError;
}
impl<V: Serialize<Ser>> Adapter for AllocAdapter<V> {
type Serializer = Ser;
type Value = V;
fn new_serializer() -> Self::Serializer {
Self::Serializer::default()
}
fn from_ser_err(e: <Self::Serializer as Fallible>::Error) -> Self::Error {
DBError::RKYV(e)
}
fn from_db_err(e: lmdb::Error) -> Self::Error {
e.into()
}
}
#[cfg(test)]
mod tests {

22
src/db/resources.rs Normal file
View File

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

View File

@ -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<Bool> { }
#[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<UInt32> { }
#[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<Vec3u8> { }
#[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<dyn SerializeValue>)>,
}
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<dyn SerializeValue>)>
}
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<V>(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(<AllocSerializer<1024> as Fallible>::Error),
}
impl From<lmdb::Error> 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: <Self::Serializer as Fallible>::Error) -> Self::Error {
StateError::RKYV(e)
}
fn from_db_err(e: lmdb::Error) -> Self::Error {
e.into()
}
}
type StateAdapter = AllocAdapter<State>;
/// State Database containing the currently set state
#[derive(Clone, Debug)]
pub struct StateDB {
/// The environment for all the databases below
env: Environment,
env: Arc<Environment>,
input: DB<StateAdapter>,
output: DB<StateAdapter>,
@ -210,7 +41,7 @@ pub struct StateDB {
}
impl StateDB {
fn open_env<P: AsRef<Path>>(path: &P) -> lmdb::Result<Environment> {
fn open_env<P: AsRef<Path>>(path: P) -> lmdb::Result<Environment> {
Environment::new()
.set_flags( EnvironmentFlags::WRITE_MAP
| EnvironmentFlags::NO_SUB_DIR
@ -221,10 +52,10 @@ impl StateDB {
}
fn new(env: Environment, input: DB<StateAdapter>, output: DB<StateAdapter>) -> Self {
Self { env, input, output }
Self { env: Arc::new(env), input, output }
}
pub fn init<P: AsRef<Path>>(path: &P) -> lmdb::Result<Self> {
pub fn init<P: AsRef<Path>>(path: P) -> lmdb::Result<Self> {
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<P: AsRef<Path>>(path: &P) -> lmdb::Result<Self> {
pub fn open<P: AsRef<Path>>(path: P) -> lmdb::Result<Self> {
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<(), <StateAdapter as Fallible>::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<(), <StateAdapter as Fallible>::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<StateAdapter>, key: u64)
-> Result<Option<LMDBorrow<RoTransaction, Archived<State>>>, 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<Option<LMDBorrow<RoTransaction, Archived<State>>>, DBError>
{ self.get(&self.input, key) }
#[inline(always)]
pub fn get_output(&self, key: u64)
-> Result<Option<LMDBorrow<RoTransaction, Archived<State>>>, 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<Option<LMDBorrow<RoTransaction, Archived<State>>>, DBError>
{
self.db.get_input(self.key)
}
pub fn get_output(&self)
-> Result<Option<LMDBorrow<RoTransaction, Archived<State>>>, 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)]

View File

@ -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) -> <Self as Fallible>::Error;
}
struct AdapterPrettyPrinter<A: Adapter>(PhantomData<A>);
impl<A: Adapter> AdapterPrettyPrinter<A> {
pub fn new() -> Self { Self(PhantomData) }
}
impl<A: Adapter> fmt::Debug for AdapterPrettyPrinter<A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct(&type_name::<A>())
.field("serializer", &type_name::<A::Serializer>())
.field("value", &type_name::<A::Value>())
.finish()
}
}
pub trait OutputBuffer {
type Buffer: AsRef<[u8]>;
fn into_slice(self) -> Self::Buffer;
@ -59,6 +76,22 @@ pub struct DB<A> {
db: RawDB,
phantom: PhantomData<A>,
}
impl<A> Clone for DB<A> {
fn clone(&self) -> Self {
Self {
db: self.db.clone(),
phantom: PhantomData,
}
}
}
impl<A: Adapter> fmt::Debug for DB<A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DB")
.field("db", &self.db)
.field("adapter", &AdapterPrettyPrinter::<A>::new())
.finish()
}
}
impl<A> DB<A> {
fn new(db: RawDB) -> Self {
@ -167,6 +200,12 @@ impl<'txn, C, A> Cursor<C, A>
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<K: AsRef<[u8]>>(&mut self, key: &K) -> Iter<'txn, A> {
let iter = self.cursor.iter_dup_of(key);
// Safe because `new` isn't :P

View File

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

View File

@ -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<Arc<State>>;
type ResourceStateSignal = MutableSignalCloned<Arc<State>>;
use crate::error::Result;
pub type MachineMap = HashMap<String, Machine>;
pub type ActorMap = HashMap<String, Mutex<mpsc::Sender<Option<ActorSignal>>>>;
pub type InitMap = HashMap<String, Mutable<Option<Machine>>>;
#[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<u64, ResourceState>,
}
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())
}
}

837
src/oid.rs Normal file
View File

@ -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<u8> = 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<String> for ObjectIdentifierRoot {
fn into(self) -> String {
format!("{}", self as u8)
}
}
impl TryFrom<u8> for ObjectIdentifierRoot {
type Error = ObjectIdentifierError;
fn try_from(value: u8) -> Result<ObjectIdentifierRoot, Self::Error> {
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<Node>,
}
impl ObjectIdentifier {
const fn new(root: ObjectIdentifierRoot, first_node: u8, child_nodes: Vec<Node>)
-> Self
{
Self { root, first_node, child_nodes }
}
}
impl Archive for ObjectIdentifier {
type Archived = ArchivedVec<u8>;
type Resolver = VecResolver;
unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) {
let vec: Vec<u8> = self.clone().into();
vec.resolve(pos, resolver, out);
}
}
impl<S: Fallible> Serialize<S> for ObjectIdentifier
where Vec<u8>: Serialize<S>
{
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
let vec: Vec<u8> = self.clone().into();
vec.serialize(serializer)
}
}
fn parse_string_first_node(
nodes: &mut dyn Iterator<Item = &str>,
) -> Result<u8, ObjectIdentifierError> {
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<Item = &str>,
) -> Result<Vec<Node>, ObjectIdentifierError> {
let mut result: Vec<Node> = vec![];
while let Some(node) = nodes.next() {
result.push(
node.parse()
.map_err(|_| ObjectIdentifierError::IllegalChildNodeValue)?,
);
}
Ok(result)
}
impl ObjectIdentifier {
fn from_string<S>(value: S) -> Result<ObjectIdentifier, ObjectIdentifierError>
where
S: Into<String>,
{
let value = value.into();
let mut nodes = value.split(".");
match &nodes.next() {
Some(root_node_value) => {
let root_node_value: Result<u8, _> = root_node_value.parse();
match root_node_value {
Ok(root_node) => {
let root_node: Result<ObjectIdentifierRoot, _> = 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<String> 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<String> for ObjectIdentifier {
fn into(self) -> String {
(&self).into()
}
}
impl Into<Vec<u8>> for &ObjectIdentifier {
fn into(self) -> Vec<u8> {
let mut result: Vec<u8> = 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<u8> = 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<Vec<u8>> for ObjectIdentifier {
fn into(self) -> Vec<u8> {
(&self).into()
}
}
impl TryFrom<&str> for ObjectIdentifier {
type Error = ObjectIdentifierError;
fn try_from(value: &str) -> Result<ObjectIdentifier, Self::Error> {
ObjectIdentifier::from_string(value)
}
}
impl TryFrom<String> for ObjectIdentifier {
type Error = ObjectIdentifierError;
fn try_from(value: String) -> Result<ObjectIdentifier, Self::Error> {
ObjectIdentifier::from_string(value)
}
}
impl TryFrom<&[u8]> for ObjectIdentifier {
type Error = ObjectIdentifierError;
fn try_from(value: &[u8]) -> Result<ObjectIdentifier, Self::Error> {
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<Vec<u8>> for ObjectIdentifier {
type Error = ObjectIdentifierError;
fn try_from(value: Vec<u8>) -> Result<ObjectIdentifier, Self::Error> {
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<E>(self, v: &[u8]) -> Result<Self::Value, E>
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<E>(self, v: &str) -> Result<Self::Value, E>
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<D>(deserializer: D) -> Result<ObjectIdentifier, D::Error>
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<S>(
&self,
serializer: S,
) -> Result<<S as ser::Serializer>::Ok, <S as ser::Serializer>::Error>
where
S: ser::Serializer,
{
if serializer.is_human_readable() {
let encoded: String = self.into();
serializer.serialize_str(&encoded)
} else {
let encoded: Vec<u8> = 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<u8> = 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<u8> = 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#"<MyStruct><oid>1.2.3.5.8.13.21</oid></MyStruct>"#;
let actual = serde_xml_rs::to_string(&mydata).unwrap();
assert_eq!(expected, actual);
}
#[test]
fn xml_serde_deserialize_element() {
let src = r#"<mystruct><oid>1.2.3.5.8.13.21</oid></mystruct>"#;
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#"<mystruct oid="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 encode_binary_root_node_0() {
let expected: Vec<u8> = vec![0];
let oid = ObjectIdentifier {
root: ObjectIdentifierRoot::ItuT,
first_node: 0x00,
child_nodes: vec![],
};
let actual: Vec<u8> = (&oid).into();
assert_eq!(expected, actual);
}
#[test]
fn encode_binary_root_node_1() {
let expected: Vec<u8> = vec![40];
let oid = ObjectIdentifier {
root: ObjectIdentifierRoot::Iso,
first_node: 0x00,
child_nodes: vec![],
};
let actual: Vec<u8> = (&oid).into();
assert_eq!(expected, actual);
}
#[test]
fn encode_binary_root_node_2() {
let expected: Vec<u8> = vec![80];
let oid = ObjectIdentifier {
root: ObjectIdentifierRoot::JointIsoItuT,
first_node: 0x00,
child_nodes: vec![],
};
let actual: Vec<u8> = (&oid).into();
assert_eq!(expected, actual);
}
#[test]
fn encode_binary_example_1() {
let expected: Vec<u8> = 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<u8> = (&oid).into();
assert_eq!(expected, actual);
}
#[test]
fn encode_binary_example_2() {
let expected: Vec<u8> = 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<u8> = (&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<ObjectIdentifier, ObjectIdentifierError> =
Err(ObjectIdentifierError::IllegalRootNode);
let actual = "wtf".try_into();
assert_eq!(expected, actual);
}
#[test]
fn parse_string_empty() {
let expected: Result<ObjectIdentifier, ObjectIdentifierError> =
Err(ObjectIdentifierError::IllegalRootNode);
let actual = String::new().try_into();
assert_eq!(expected, actual);
}
#[test]
fn parse_binary_empty() {
let expected: Result<ObjectIdentifier, ObjectIdentifierError> =
Err(ObjectIdentifierError::IllegalRootNode);
let actual = vec![].try_into();
assert_eq!(expected, actual);
}
#[test]
fn parse_binary_example_over_u128() {
let expected: Result<ObjectIdentifier, ObjectIdentifierError> =
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<ObjectIdentifier, ObjectIdentifierError> =
Err(ObjectIdentifierError::IllegalRootNode);
let actual = format!("{}", i).try_into();
assert_eq!(expected, actual);
}
}
#[test]
fn parse_string_example_over_u128() {
let expected: Result<ObjectIdentifier, ObjectIdentifierError> =
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<ObjectIdentifier, ObjectIdentifierError> =
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<u8> = ObjectIdentifier {
root: ObjectIdentifierRoot::Iso,
first_node: 2,
child_nodes: vec![3, 4],
}
.into();
assert_eq!(expected, actual);
}
}

View File

@ -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<State, Error>;
async fn update(&mut self, input: &State /*, internal: &State*/) -> Result<State, DBError>;
}
pub struct Update {
pub state: State,
pub errchan: oneshot::Sender<Error>,
pub errchan: oneshot::Sender<DBError>,
}
pub struct ResourceDriver {
// putput
res: Box<dyn Resource>,
db: StateDB,
// input
rx: Receiver<Update>,
// output
db: StateAccessor,
signal: Mutable<State>,
}
@ -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);
}
}
}

115
src/state/mod.rs Normal file
View File

@ -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<dyn SerializeDynValue>,
}
#[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<StateEntry>,
}
impl PartialEq for State {
fn eq(&self, other: &Self) -> bool {
self.hash == other.hash
}
}
impl PartialEq<Archived<State>> for State {
fn eq(&self, other: &Archived<State>) -> 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<StateEntry>
}
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<V>(mut self, key: ObjectIdentifier<>, val: Box<V>) -> 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
}
}

387
src/state/value.rs Normal file
View File

@ -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<T> 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<dyn Value>;
}
#[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<dyn Value>,
}
impl<'a> serde::Serialize for Entry<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<D>(deserializer: D) -> Result<Self, D::Error>
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<A: serde::de::MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error>
{
// 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<u8> = 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<dyn Value> = 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<dyn Value>);
impl<'de> serde::de::DeserializeSeed<'de> for ValueSeed {
type Value = Box<dyn Value>;
fn deserialize<D>(mut self, deserializer: D) -> Result<Self::Value, D::Error>
where D: serde::Deserializer<'de>
{
let mut deser = <dyn erased_serde::Deserializer>::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<bool> {
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<usize, DynError>;
fn archived_type_oid(&self) -> ObjectIdentifier;
}
impl<T> SerializeValue for T
where T: for<'a> Serialize<dyn DynSerializer + 'a>,
T::Archived: TypeOid,
{
fn serialize_val(&self, serializer: &mut dyn DynSerializer) -> Result<usize, DynError> {
serializer.serialize_value(self)
}
fn archived_type_oid(&self) -> ObjectIdentifier {
Archived::<T>::get_type_oid()
}
}
trait DeserializeValue<T: Pointee + ?Sized> {
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<T::Metadata, DynError>;
}
pub struct ArchivedValueMetadata<T: ?Sized> {
type_oid: Archived<ObjectIdentifier>,
phantom: PhantomData<T>,
}
impl<T: TypeOid + ?Sized> ArchivedValueMetadata<T> {
pub unsafe fn emplace(type_oid: Archived<ObjectIdentifier>, 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<T> {
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<T: TypeOid>() -> Self {
let oid: Vec<u8> = 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<T: ?Sized>(&self) -> DynMetadata<T> {
core::mem::transmute(self.vtable)
}
}
struct ImplEntry<'a> {
id: ImplId<'a>,
data: ImplData,
}
inventory::collect!(ImplEntry<'static>);
impl ImplEntry<'_> {
#[doc(hidden)]
pub fn new<T: TypeOid + RegisteredImpl>() -> Self {
Self {
id: ImplId::new::<T>(),
data: ImplData {
vtable: <T as RegisteredImpl>::vtable(),
},
}
}
}
struct ImplRegistry {
oid_to_data: HashMap<ImplId<'static>, 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<ImplData> {
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::<ImplEntry> {
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::<bool>() as *const dyn Value
))
}
}
}
inventory::submit! {ImplEntry::new::<bool>()}
#[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<Vec3u8> {}
#[cfg(test)]
mod tests {
}