use std::collections::HashMap;
use std::collections::HashSet;
use postcard::ser_flavors::Flavor as _;
use serde::Deserialize;
use serde::Serialize;
use crate::arc_erase::ArcEraseDyn;
use crate::flavors::PagableSlice;
use crate::flavors::PagableVecFlavor;
use crate::flavors::SharedPosition;
use crate::storage::data::DataKey;
use crate::storage::data::PagableData;
use crate::storage::handle::PagableStorageHandle;
use crate::storage::traits::PagableStorage;
use crate::traits::PagableCursor;
use crate::traits::PagableDeserializer;
use crate::traits::PagableSerializer;
use crate::traits::SessionContext;
pub struct TestingSerializer {
serde: postcard::Serializer<PagableVecFlavor>,
seen_arcs: HashSet<usize>,
arc_count: usize,
session_context: SessionContext,
}
impl TestingSerializer {
pub fn new() -> Self {
Self {
serde: postcard::Serializer {
output: PagableVecFlavor::new(),
},
seen_arcs: HashSet::new(),
arc_count: 0,
session_context: SessionContext::new(),
}
}
pub fn finish(self) -> Vec<u8> {
self.serde.output.finalize().unwrap()
}
}
impl Default for TestingSerializer {
fn default() -> Self {
Self::new()
}
}
impl PagableSerializer for TestingSerializer {
fn serde(&mut self) -> &mut postcard::Serializer<PagableVecFlavor> {
&mut self.serde
}
fn serialize_arc(&mut self, arc: &dyn ArcEraseDyn) -> crate::Result<()> {
let identity = arc.identity();
identity.serialize(self.serde())?;
if self.seen_arcs.insert(identity) {
arc.serialize(self)?;
}
self.arc_count += 1;
Ok(())
}
fn position(&mut self) -> PagableCursor {
PagableCursor {
byte_pos: self.serde.output.position(),
arc_index: self.arc_count,
}
}
fn session_context(&mut self) -> &SessionContext {
&self.session_context
}
}
pub struct TestingDeserializer<'de> {
pos: SharedPosition,
serde: postcard::Deserializer<'de, PagableSlice<'de>>,
seen_arcs: HashMap<usize, Box<dyn ArcEraseDyn>>,
arc_index: usize,
storage: PagableStorageHandle,
}
impl<'de> TestingDeserializer<'de> {
pub fn new(bytes: &'de [u8]) -> Self {
let pos = SharedPosition::new();
Self {
pos: pos.clone(),
serde: postcard::Deserializer::from_flavor(PagableSlice::new(bytes, pos)),
seen_arcs: HashMap::new(),
arc_index: 0,
storage: PagableStorageHandle::new(std::sync::Arc::new(EmptyPagableStorage::new())),
}
}
}
impl<'de> PagableDeserializer<'de> for TestingDeserializer<'de> {
fn serde(&mut self) -> Box<dyn erased_serde::Deserializer<'de> + '_> {
Box::new(<dyn erased_serde::Deserializer>::erase(&mut self.serde))
}
fn position(&self) -> PagableCursor {
PagableCursor {
byte_pos: self.pos.get(),
arc_index: self.arc_index,
}
}
unsafe fn seek(&mut self, cursor: PagableCursor) {
self.pos.set(cursor.byte_pos);
self.arc_index = cursor.arc_index;
}
fn deserialize_arc(
&mut self,
_type_id: std::any::TypeId,
deserialize_fn: for<'a> fn(
&mut dyn PagableDeserializer<'a>,
) -> crate::Result<Box<dyn ArcEraseDyn>>,
) -> crate::Result<Box<dyn ArcEraseDyn>> {
let identity: usize = Deserialize::deserialize(&mut self.serde)?;
self.arc_index += 1;
if let Some(arc_dyn) = self.seen_arcs.get(&identity) {
Ok(arc_dyn.clone_dyn())
} else {
let arc = deserialize_fn(self)?;
self.seen_arcs.insert(identity, arc.clone_dyn());
Ok(arc)
}
}
fn storage(&self) -> PagableStorageHandle {
self.storage.clone()
}
fn as_dyn(&mut self) -> &mut dyn crate::traits::PagableDeserializer<'de> {
self
}
fn session_context(&self) -> &SessionContext {
self.storage.backing_storage().session_context()
}
}
pub(crate) struct EmptyPagableStorage {
session_context: SessionContext,
}
impl EmptyPagableStorage {
pub(crate) fn new() -> Self {
Self {
session_context: SessionContext::new(),
}
}
}
#[async_trait::async_trait]
impl PagableStorage for EmptyPagableStorage {
fn fetch_arc_or_data_blocking(
&self,
_type_id: &std::any::TypeId,
_key: &DataKey,
) -> anyhow::Result<either::Either<Box<dyn ArcEraseDyn>, std::sync::Arc<PagableData>>> {
Err(anyhow::anyhow!(
"No storage available for testing deserializer"
))
}
async fn fetch_data(&self, _key: &DataKey) -> anyhow::Result<std::sync::Arc<PagableData>> {
Err(anyhow::anyhow!(
"No storage available for testing deserializer"
))
}
fn on_arc_deserialized(
&self,
_typeid: std::any::TypeId,
_key: DataKey,
_arc: Box<dyn ArcEraseDyn>,
) -> Option<Box<dyn ArcEraseDyn>> {
None
}
fn schedule_for_paging(&self, _arc: Box<dyn ArcEraseDyn>) {
}
fn session_context(&self) -> &SessionContext {
&self.session_context
}
fn store_data(&self, data: PagableData) -> anyhow::Result<DataKey> {
Ok(data.compute_key())
}
}