mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-22 06:47:56 +01:00
the worst part of all of this is that it works :D
This commit is contained in:
parent
33131f38c4
commit
8d7a4ac5be
3
src/bin/bffhd.rs
Normal file
3
src/bin/bffhd.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
diflouroborane::main()
|
||||
}
|
@ -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() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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>,
|
||||
|
@ -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
22
src/db/resources.rs
Normal 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>>,
|
||||
}
|
261
src/db/state.rs
261
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<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)]
|
||||
|
@ -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
|
||||
|
@ -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() {
|
@ -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
837
src/oid.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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
115
src/state/mod.rs
Normal 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
387
src/state/value.rs
Normal 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 {
|
||||
}
|
Loading…
Reference in New Issue
Block a user