mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-22 14:57: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>
|
impl<'env, T, V> LMDBorrow<T, V>
|
||||||
where T: Transaction,
|
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, }
|
Self { ptr: ptr.into(), txn, }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -37,5 +40,3 @@ impl<'env, T, V> Deref for LMDBorrow<T, V>
|
|||||||
unsafe { self.ptr.as_ref() }
|
unsafe { self.ptr.as_ref() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ pub struct Entry<K: Archive, V: Archive> {
|
|||||||
pub val: V,
|
pub val: V,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub struct HashAdapter<K, A> {
|
pub struct HashAdapter<K, A> {
|
||||||
k: PhantomData<K>,
|
k: PhantomData<K>,
|
||||||
a: PhantomData<A>,
|
a: PhantomData<A>,
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
use std::{
|
||||||
|
marker::PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
pub use lmdb::{
|
pub use lmdb::{
|
||||||
Environment,
|
Environment,
|
||||||
|
|
||||||
@ -10,6 +14,12 @@ pub use lmdb::{
|
|||||||
RwTransaction,
|
RwTransaction,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use rkyv::{
|
||||||
|
Fallible,
|
||||||
|
Serialize,
|
||||||
|
ser::serializers::AllocSerializer,
|
||||||
|
};
|
||||||
|
|
||||||
mod raw;
|
mod raw;
|
||||||
use raw::RawDB;
|
use raw::RawDB;
|
||||||
|
|
||||||
@ -33,6 +43,52 @@ pub use hash::{
|
|||||||
mod fix;
|
mod fix;
|
||||||
pub use fix::LMDBorrow;
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
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::{
|
use std::{
|
||||||
fmt,
|
sync::Arc,
|
||||||
|
|
||||||
any::Any,
|
|
||||||
|
|
||||||
collections::{
|
|
||||||
hash_map::DefaultHasher
|
|
||||||
},
|
|
||||||
hash::{
|
|
||||||
Hash,
|
|
||||||
Hasher
|
|
||||||
},
|
|
||||||
|
|
||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
|
|
||||||
use rkyv::{
|
use rkyv::Archived;
|
||||||
Archive,
|
|
||||||
Archived,
|
|
||||||
|
|
||||||
Serialize,
|
use super::{
|
||||||
Deserialize,
|
|
||||||
|
|
||||||
out_field,
|
|
||||||
|
|
||||||
Fallible,
|
|
||||||
ser::serializers::AllocSerializer,
|
|
||||||
};
|
|
||||||
use rkyv_dyn::{
|
|
||||||
archive_dyn,
|
|
||||||
};
|
|
||||||
use rkyv_typename::TypeName;
|
|
||||||
|
|
||||||
use crate::db::{
|
|
||||||
DB,
|
DB,
|
||||||
Environment,
|
Environment,
|
||||||
|
|
||||||
@ -40,168 +14,25 @@ use crate::db::{
|
|||||||
WriteFlags,
|
WriteFlags,
|
||||||
|
|
||||||
Adapter,
|
Adapter,
|
||||||
|
AllocAdapter,
|
||||||
|
DBError,
|
||||||
|
|
||||||
Transaction,
|
Transaction,
|
||||||
|
RoTransaction,
|
||||||
RwTransaction,
|
RwTransaction,
|
||||||
|
|
||||||
|
LMDBorrow,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[archive_dyn(deserialize)]
|
use crate::state::State;
|
||||||
/// 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 { }
|
|
||||||
|
|
||||||
#[repr(transparent)]
|
type StateAdapter = AllocAdapter<State>;
|
||||||
#[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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// State Database containing the currently set state
|
/// State Database containing the currently set state
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct StateDB {
|
pub struct StateDB {
|
||||||
/// The environment for all the databases below
|
/// The environment for all the databases below
|
||||||
env: Environment,
|
env: Arc<Environment>,
|
||||||
|
|
||||||
input: DB<StateAdapter>,
|
input: DB<StateAdapter>,
|
||||||
output: DB<StateAdapter>,
|
output: DB<StateAdapter>,
|
||||||
@ -210,7 +41,7 @@ pub struct StateDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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()
|
Environment::new()
|
||||||
.set_flags( EnvironmentFlags::WRITE_MAP
|
.set_flags( EnvironmentFlags::WRITE_MAP
|
||||||
| EnvironmentFlags::NO_SUB_DIR
|
| EnvironmentFlags::NO_SUB_DIR
|
||||||
@ -221,10 +52,10 @@ impl StateDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new(env: Environment, input: DB<StateAdapter>, output: DB<StateAdapter>) -> Self {
|
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 env = Self::open_env(path)?;
|
||||||
let input = unsafe {
|
let input = unsafe {
|
||||||
DB::create(&env, Some("input"), DatabaseFlags::INTEGER_KEY)?
|
DB::create(&env, Some("input"), DatabaseFlags::INTEGER_KEY)?
|
||||||
@ -236,7 +67,7 @@ impl StateDB {
|
|||||||
Ok(Self::new(env, input, output))
|
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 env = Self::open_env(path)?;
|
||||||
let input = unsafe { DB::open(&env, Some("input"))? };
|
let input = unsafe { DB::open(&env, Some("input"))? };
|
||||||
let output = unsafe { DB::open(&env, Some("output"))? };
|
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)
|
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 flags = WriteFlags::empty();
|
||||||
let k = key.to_ne_bytes();
|
let k = key.to_ne_bytes();
|
||||||
@ -254,14 +85,68 @@ impl StateDB {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&self, key: u64, input: &State, output: &State)
|
pub fn update(&self, key: u64, input: &State, output: &State)
|
||||||
-> Result<(), <StateAdapter as Fallible>::Error>
|
-> Result<(), DBError>
|
||||||
{
|
{
|
||||||
let mut txn = self.env.begin_rw_txn().map_err(StateAdapter::from_db_err)?;
|
let mut txn = self.env.begin_rw_txn().map_err(StateAdapter::from_db_err)?;
|
||||||
self.update_txn(&mut txn, key, input, output)?;
|
self.update_txn(&mut txn, key, input, output)?;
|
||||||
|
|
||||||
txn.commit().map_err(StateAdapter::from_db_err)
|
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)]
|
#[cfg(test)]
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
|
fmt,
|
||||||
|
any::type_name,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -39,6 +41,21 @@ pub trait Adapter: Fallible {
|
|||||||
fn from_db_err(e: lmdb::Error) -> <Self as Fallible>::Error;
|
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 {
|
pub trait OutputBuffer {
|
||||||
type Buffer: AsRef<[u8]>;
|
type Buffer: AsRef<[u8]>;
|
||||||
fn into_slice(self) -> Self::Buffer;
|
fn into_slice(self) -> Self::Buffer;
|
||||||
@ -59,6 +76,22 @@ pub struct DB<A> {
|
|||||||
db: RawDB,
|
db: RawDB,
|
||||||
phantom: PhantomData<A>,
|
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> {
|
impl<A> DB<A> {
|
||||||
fn new(db: RawDB) -> Self {
|
fn new(db: RawDB) -> Self {
|
||||||
@ -167,6 +200,12 @@ impl<'txn, C, A> Cursor<C, A>
|
|||||||
Self { cursor, phantom: PhantomData }
|
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> {
|
pub fn iter_dup_of<K: AsRef<[u8]>>(&mut self, key: &K) -> Iter<'txn, A> {
|
||||||
let iter = self.cursor.iter_dup_of(key);
|
let iter = self.cursor.iter_dup_of(key);
|
||||||
// Safe because `new` isn't :P
|
// Safe because `new` isn't :P
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
#![forbid(unused_imports)]
|
#![forbid(unused_imports)]
|
||||||
|
|
||||||
extern crate async_trait;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
mod modules;
|
mod modules;
|
||||||
mod log;
|
mod log;
|
||||||
@ -19,11 +17,16 @@ mod initiator;
|
|||||||
mod space;
|
mod space;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::oid::ObjectIdentifier;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use crate::state::value::{UInt32, Vec3u8, SerializeValue};
|
||||||
|
|
||||||
mod resource;
|
mod resource;
|
||||||
mod schema;
|
mod schema;
|
||||||
mod state;
|
mod state;
|
||||||
mod error;
|
|
||||||
mod db;
|
mod db;
|
||||||
|
mod network;
|
||||||
|
mod oid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
@ -47,7 +50,32 @@ use crate::config::Config;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pub fn main() {
|
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() {
|
/*fn main() {
|
@ -1,82 +1,25 @@
|
|||||||
use std::fmt;
|
use std::{
|
||||||
|
sync::Arc,
|
||||||
|
collections::HashMap,
|
||||||
|
};
|
||||||
|
|
||||||
use std::sync::Mutex;
|
use futures_signals::signal::{
|
||||||
use std::collections::HashMap;
|
Mutable,
|
||||||
|
MutableSignalCloned
|
||||||
|
};
|
||||||
|
|
||||||
use futures::channel::mpsc;
|
use crate::state::State;
|
||||||
use futures_signals::signal::Mutable;
|
|
||||||
|
|
||||||
use crate::machine::Machine;
|
type ResourceState = Mutable<Arc<State>>;
|
||||||
use crate::actor::ActorSignal;
|
type ResourceStateSignal = MutableSignalCloned<Arc<State>>;
|
||||||
|
|
||||||
use crate::error::Result;
|
/// Connection Broker between Resources and Subscribers
|
||||||
|
|
||||||
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
|
|
||||||
///
|
///
|
||||||
/// Network as per FRP, not the one with packages and frames
|
/// This serves as touch-off point between resources and anybody else. It doesn't drive
|
||||||
// TODO De/Serialize established connection on startup/shutdown.
|
/// any state updates, it only allows subscribers to subscribe to the resources that are
|
||||||
|
/// driving the state updates
|
||||||
pub struct Network {
|
pub struct Network {
|
||||||
inits: InitMap,
|
sources: HashMap<u64, ResourceState>,
|
||||||
|
|
||||||
// Store connections
|
|
||||||
//miconn: Vec<(String, String)>,
|
|
||||||
|
|
||||||
pub machines: MachineMap,
|
|
||||||
|
|
||||||
// Store connections
|
|
||||||
//maconn: Vec<(String, String)>,
|
|
||||||
|
|
||||||
actors: ActorMap,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 smol::channel::Receiver;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::state::State;
|
||||||
use crate::state::{State, StateDB};
|
use crate::db::{
|
||||||
|
state::StateAccessor,
|
||||||
|
DBError,
|
||||||
|
};
|
||||||
|
|
||||||
/// A resource in BFFH has to contain several different parts;
|
/// A resource in BFFH has to contain several different parts;
|
||||||
/// - Currently set state
|
/// - 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
|
/// - Check authorization of updates i.e. is this user allowed to do that
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Resource {
|
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
|
/// Run whatever internal logic this resource has for the given State update, and return the
|
||||||
/// new output state that this update produces.
|
/// 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 struct Update {
|
||||||
pub state: State,
|
pub state: State,
|
||||||
pub errchan: oneshot::Sender<Error>,
|
pub errchan: oneshot::Sender<DBError>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ResourceDriver {
|
pub struct ResourceDriver {
|
||||||
|
// putput
|
||||||
res: Box<dyn Resource>,
|
res: Box<dyn Resource>,
|
||||||
db: StateDB,
|
|
||||||
|
|
||||||
|
// input
|
||||||
rx: Receiver<Update>,
|
rx: Receiver<Update>,
|
||||||
|
|
||||||
|
// output
|
||||||
|
db: StateAccessor,
|
||||||
|
|
||||||
signal: Mutable<State>,
|
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
|
// 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.
|
// internal logic of the resource has done to make this happen.
|
||||||
// Another half right solution is to unwrap and recreate everything.
|
// Another half right solution is to unwrap and recreate everything.
|
||||||
//self.db.store(&state, &outstate);
|
// "Best" solution would be to tell the resource to rollback their interal
|
||||||
self.signal.set_neq(outstate);
|
// 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) => {
|
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