use std::{ collections::hash_map::DefaultHasher, fmt, hash::{ Hash, Hasher }, }; use std::fmt::Formatter; use std::ops::Deref; use rkyv::{ Archive, Archived, Deserialize, out_field, Serialize, }; use serde::de::{Error, MapAccess}; use serde::Deserializer; use serde::ser::SerializeMap; use value::{RegisteredImpl, SerializeValue}; use crate::utils::oid::ObjectIdentifier; use crate::resource::state::value::{DynOwnedVal, DynVal, TypeOid, }; pub mod value; pub mod db; #[derive(serde::Serialize, serde::Deserialize)] #[derive(Archive, Serialize, Deserialize)] #[derive(Clone, PartialEq)] #[archive_attr(derive(Debug))] /// 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 { pub hash: u64, pub inner: Vec, } impl State { pub fn build() -> StateBuilder { StateBuilder::new() } pub fn hash(&self) -> u64 { self.hash } } impl PartialEq> for State { fn eq(&self, other: &Archived) -> bool { self.hash == other.hash } } impl Eq for State {} impl fmt::Debug for State { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut sf = f.debug_struct("State"); for OwnedEntry { oid, val } in self.inner.iter() { let k: String = oid.into(); sf.field(k.as_ref(), val); } sf.finish() } } #[derive(Debug)] pub struct StateBuilder { hasher: DefaultHasher, inner: Vec } impl StateBuilder { pub fn new() -> Self { let hasher = DefaultHasher::new(); Self { inner: Vec::new(), hasher } } pub fn finish(self) -> State { State { hash: self.hasher.finish(), inner: self.inner, } } /// Add key-value pair to the State being built. /// /// We have to use this split system here because type erasure prevents us from limiting values /// to `Hash`. Specifically, you can't have a trait object of `Hash` because `Hash` depends on /// `Self`. In this function however the compiler still knows the exact type of `V` and can /// call statically call its `hash` method. pub fn add(mut self, oid: ObjectIdentifier, val: Box) -> Self where V: SerializeValue + Hash + Archive, Archived: TypeOid + RegisteredImpl, { // Hash before creating the StateEntry struct which removes the type information oid.hash(&mut self.hasher); val.hash(&mut self.hasher); self.inner.push(OwnedEntry { oid, val }); self } } #[derive(Debug)] pub struct Entry<'a> { pub oid: &'a ObjectIdentifier, pub val: &'a dyn SerializeValue, } #[derive(Debug, Clone, Archive, Serialize, Deserialize)] #[archive_attr(derive(Debug))] pub struct OwnedEntry { pub oid: ObjectIdentifier, pub val: Box, } impl PartialEq for OwnedEntry { fn eq(&self, other: &Self) -> bool { self.oid == other.oid && self.val.dyn_eq(other.val.as_value()) } } 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, &DynVal(self.val))?; ser.end() } } impl serde::Serialize for OwnedEntry { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { let mut ser = serializer.serialize_map(Some(1))?; ser.serialize_entry(&self.oid, &DynVal(self.val.deref()))?; ser.end() } } impl<'de> serde::Deserialize<'de> for OwnedEntry { fn deserialize(deserializer: D) -> Result where D: 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 { let oid: ObjectIdentifier = map.next_key()? .ok_or(A::Error::missing_field("oid"))?; let val: DynOwnedVal = map.next_value()?; Ok(OwnedEntry { oid, val: val.0 }) } } #[cfg(test)] pub mod tests { use super::*; use super::value::*; pub(crate) fn gen_random() -> State { let amt: u8 = rand::random::() % 20; let mut sb = State::build(); for _ in 0..amt { let oid = crate::utils::oid::tests::gen_random(); sb = match rand::random::()%12 { 0 => sb.add(oid, Box::new(rand::random::())), 1 => sb.add(oid, Box::new(rand::random::())), 2 => sb.add(oid, Box::new(rand::random::())), 3 => sb.add(oid, Box::new(rand::random::())), 4 => sb.add(oid, Box::new(rand::random::())), 5 => sb.add(oid, Box::new(rand::random::())), 6 => sb.add(oid, Box::new(rand::random::())), 7 => sb.add(oid, Box::new(rand::random::())), 8 => sb.add(oid, Box::new(rand::random::())), 9 => sb.add(oid, Box::new(rand::random::())), 10 => sb.add(oid, Box::new(rand::random::())), 11 => sb.add(oid, Box::new(rand::random::())), _ => unreachable!(), } } sb.finish() } #[test] fn test_equal_state_is_eq() { let stateA = State::build() .add(OID_POWERED.clone(), Box::new(false)) .add(OID_INTENSITY.clone(), Box::new(1024)) .finish(); let stateB = State::build() .add(OID_POWERED.clone(), Box::new(false)) .add(OID_INTENSITY.clone(), Box::new(1024)) .finish(); assert_eq!(stateA, stateB); } #[test] fn test_unequal_state_is_ne() { let stateA = State::build() .add(OID_POWERED.clone(), Box::new(true)) .add(OID_INTENSITY.clone(), Box::new(512)) .finish(); let stateB = State::build() .add(OID_POWERED.clone(), Box::new(false)) .add(OID_INTENSITY.clone(), Box::new(1024)) .finish(); assert_ne!(stateA, stateB); } #[test] fn test_state_is_clone() { let stateA = gen_random(); let stateB = stateA.clone(); let stateC = stateB.clone(); drop(stateA); assert_eq!(stateC, stateB); } }