use core::{ ptr, }; use std::{ fmt, any::Any, hash::Hash, ops::Deref, convert::TryFrom, }; use rkyv::{Archive, Archived, Serialize, Deserialize, out_field, }; use rkyv_dyn::{archive_dyn, DynSerializer, DynError, DynDeserializer}; use rkyv_typename::TypeName; use ptr_meta::{DynMetadata, Pointee}; use std::marker::PhantomData; use inventory; use crate::oid::{ObjectIdentifier}; use rkyv::ser::{Serializer, }; use std::collections::HashMap; use std::alloc::Layout; use serde::ser::SerializeMap; use std::fmt::Formatter; use serde::de::Error as _; pub trait Value: fmt::Debug + erased_serde::Serialize { fn deserialize_val_in_place<'de>(&mut self, deserializer: &mut dyn erased_serde::Deserializer<'de>) -> Result<(), erased_serde::Error>; } erased_serde::serialize_trait_object!(Value); impl Value for T where T: fmt::Debug + Archive + erased_serde::Serialize + for<'de> serde::Deserialize<'de> { fn deserialize_val_in_place<'de>(&mut self, deserializer: &mut dyn erased_serde::Deserializer<'de>) -> Result<(), erased_serde::Error> { *self = erased_serde::deserialize(deserializer)?; Ok(()) } } impl Pointee for dyn Value { type Metadata = DynMetadata; } #[derive(Debug)] pub struct Entry<'a> { pub oid: &'a ObjectIdentifier, pub val: &'a dyn Value, } #[derive(Debug)] pub struct OwnedEntry { pub oid: ObjectIdentifier, pub val: Box, } impl<'a> serde::Serialize for Entry<'a> { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { let mut ser = serializer.serialize_map(Some(1))?; ser.serialize_entry(self.oid, self.val)?; ser.end() } } impl<'de> serde::Deserialize<'de> for OwnedEntry { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de> { deserializer.deserialize_map(OwnedEntryVisitor) } } struct OwnedEntryVisitor; impl<'de> serde::de::Visitor<'de> for OwnedEntryVisitor { type Value = OwnedEntry; fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { write!(formatter, "an one entry map from OID to some value object") } fn visit_map>(self, mut map: A) -> Result { // Bad magic code. Problem we have to solve: We only know how to parse whatever comes // after the OID after having looked at the OID. We have zero static type info available // during deserialization. Soooooo: // Get OID first. That's easy, we know it's the key, we know how to read it. let oid: ObjectIdentifier = map.next_key()? .ok_or(A::Error::missing_field("oid"))?; let b: Vec = oid.clone().into(); // Get the Value vtable for that OID. Or fail because we don't know that OID, either works. let valimpl = IMPL_REGISTRY.get(ImplId::from_type_oid(&b)) .ok_or(serde::de::Error::invalid_value( serde::de::Unexpected::Other("unknown oid"), &"oid an implementation was registered for" ))?; // Casting random usize you find on the side of the road as vtable on unchecked pointers. // What could possibly go wrong? >:D let valbox: Box = unsafe { // recreate vtable as fat ptr metadata let meta = valimpl.pointer_metadata(); // Don't bother checking here. The only way this could be bad is if the vtable above // is bad an in that case a segfault here would be *much better* than whatever is // going to happen afterwards. let layout = Layout::from_size_align_unchecked(meta.size_of(), meta.align_of()); // Hello yes I would like a Box the old fashioned way. // Oh you're asking why we're allocating stuff here and never ever bother zeroing or // validate in any other way if this is sane? // Well... let ptr: *mut () = std::alloc::alloc(layout).cast::<()>(); Box::from_raw(ptr_meta::from_raw_parts_mut(ptr, meta)) }; // ... The only way we can make Value a trait object by having it deserialize *into // it's own uninitialized representation*. Yeah don't worry, this isn't the worst part of // the game yet. >:D let seed = ValueSeed(valbox); let val = map.next_value_seed(seed)?; Ok(OwnedEntry { oid, val }) } } struct ValueSeed(Box); impl<'de> serde::de::DeserializeSeed<'de> for ValueSeed { type Value = Box; fn deserialize(mut self, deserializer: D) -> Result where D: serde::Deserializer<'de> { let mut deser = ::erase(deserializer); // Hey, better initialize late than never. Oh completely unrelated but if we unwind after // allocating the box and before completing this function call that's undefined behaviour // so maybe don't do that thanks <3 self.0.deserialize_val_in_place(&mut deser); Ok(self.0) } } pub trait TypeOid { fn get_type_oid() -> ObjectIdentifier; } impl TypeOid for Archived { fn get_type_oid() -> ObjectIdentifier { ObjectIdentifier::try_from("1.3.6.1.4.1.48398.612.1.1").unwrap() } } pub trait SerializeValue { fn serialize_val(&self, serializer: &mut dyn DynSerializer) -> Result; fn archived_type_oid(&self) -> ObjectIdentifier; } impl SerializeValue for T where T: for<'a> Serialize, T::Archived: TypeOid, { fn serialize_val(&self, serializer: &mut dyn DynSerializer) -> Result { serializer.serialize_value(self) } fn archived_type_oid(&self) -> ObjectIdentifier { Archived::::get_type_oid() } } trait DeserializeValue { unsafe fn deserialize_val( &self, deserializer: &mut dyn DynDeserializer, alloc: &mut dyn FnMut(Layout) -> *mut u8, ) -> Result<*mut (), DynError>; fn deserialize_dyn_metadata( &self, deserializer: &mut dyn DynDeserializer, ) -> Result; } pub struct ArchivedValueMetadata { type_oid: Archived, phantom: PhantomData, } impl ArchivedValueMetadata { pub unsafe fn emplace(type_oid: Archived, out: *mut Self) { ptr::addr_of_mut!((*out).type_oid).write(type_oid); } pub fn vtable(&self) -> usize { IMPL_REGISTRY .get(ImplId::from_type_oid(&self.type_oid)) .expect("Unregistered type oid") .vtable } pub fn pointer_metadata(&self) -> DynMetadata { unsafe { core::mem::transmute(self.vtable()) } } } #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] struct ImplId<'a> { type_oid: &'a [u8], } impl<'a> ImplId<'a> { fn from_type_oid(type_oid: &'a [u8]) -> Self { Self { type_oid } } } impl ImplId<'static> { fn new() -> Self { let oid: Vec = T::get_type_oid().into(); Self { type_oid: oid.leak() } } } #[derive(Copy, Clone, Debug)] struct ImplData { pub vtable: usize, // TODO DebugImpl // TODO DebugInfo } impl ImplData { pub unsafe fn pointer_metadata(&self) -> DynMetadata { core::mem::transmute(self.vtable) } } struct ImplEntry<'a> { id: ImplId<'a>, data: ImplData, } inventory::collect!(ImplEntry<'static>); impl ImplEntry<'_> { #[doc(hidden)] pub fn new() -> Self { Self { id: ImplId::new::(), data: ImplData { vtable: ::vtable(), }, } } } struct ImplRegistry { oid_to_data: HashMap, ImplData>, } impl ImplRegistry { fn new() -> Self { Self { oid_to_data: HashMap::new() } } fn add_entry(&mut self, entry: &'static ImplEntry) { let old_val = self.oid_to_data.insert(entry.id, entry.data); assert!(old_val.is_none()); } fn get(&self, type_oid: ImplId) -> Option { self.oid_to_data.get(&type_oid).map(|d| *d) } } lazy_static::lazy_static! { // FIXME: Dynamic modules *will* break this. static ref IMPL_REGISTRY: ImplRegistry = { let mut reg = ImplRegistry::new(); for entry in inventory::iter:: { reg.add_entry(entry); } reg }; } pub unsafe trait RegisteredImpl { fn vtable() -> usize; } unsafe impl RegisteredImpl for bool { fn vtable() -> usize { unsafe { core::mem::transmute(ptr_meta::metadata( core::ptr::null::() as *const dyn Value )) } } } inventory::submit! {ImplEntry::new::()} #[archive_dyn(deserialize)] /// Trait to be implemented by any value in the state map. /// /// A value can be any type not having dangling references (with the added /// restriction that it has to implement `Debug` for debugger QoL). /// In fact Value *also* needs to implement Hash since BFFH checks if the state /// is different to before on input and output before updating the resource re. /// notifying actors and notifys. This dependency is not expressable via /// supertraits since it is not possible to make Hash into a trait object. /// To solve this [`State`] uses the [`StateBuilder`] which adds an `Hash` /// requirement for inputs on [`add`](struct::StateBuilder::add). The hash is /// being created over all inserted values and then used to check for equality. /// Note that in addition to collisions, Hash is not guaranteed stable over /// ordering and will additionally not track overwrites, so if the order of /// insertions changes or values are set and later overwritten then two equal /// States can and are likely to have different hashes. pub trait DynValue: Any + fmt::Debug {} macro_rules! valtype { ( $x:ident, $y:ident ) => { #[repr(transparent)] #[derive(Debug, PartialEq, Eq, Hash)] #[derive(Archive, Serialize, Deserialize)] #[derive(serde::Serialize, serde::Deserialize)] #[archive_attr(derive(TypeName, Debug))] pub struct $x(pub $y); #[archive_dyn(deserialize)] impl DynValue for $x {} impl DynValue for Archived<$x> {} impl Deref for $x { type Target = $y; fn deref(&self) -> &Self::Target { &self.0 } } impl From<$y> for $x { fn from(e: $y) -> $x { Self(e) } } impl $x { pub fn new(e: $y) -> Self { Self(e) } pub fn into_inner(self) -> $y { self.0 } } } } valtype!(Bool, bool); valtype!(UInt8, u8); valtype!(UInt16, u16); valtype!(UInt32, u32); valtype!(UInt64, u64); valtype!(UInt128, u128); valtype!(Int8, i8); valtype!(Int16, i16); valtype!(Int32, i32); valtype!(Int64, i64); valtype!(Int128, i128); valtype!(RString, String); #[derive(serde::Serialize, serde::Deserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Archive, Serialize, Deserialize)] #[archive_attr(derive(TypeName, Debug))] pub struct Vec3u8 { pub a: u8, pub b: u8, pub c: u8, } #[archive_dyn(deserialize)] impl DynValue for Vec3u8 {} impl DynValue for Archived {} #[cfg(test)] mod tests { }