Skip to content

Instantly share code, notes, and snippets.

@Alxandr
Created February 9, 2024 16:24
Show Gist options
  • Save Alxandr/b6ce7547ba0d097801211b575f34fa04 to your computer and use it in GitHub Desktop.
Save Alxandr/b6ce7547ba0d097801211b575f34fa04 to your computer and use it in GitHub Desktop.
Owned archive (rkyv)
use std::{marker::PhantomData, ops, sync::Arc};
pub struct OwnedArchive<A, S: ArchiveStorage> {
storage: S,
pos: usize,
_marker: PhantomData<A>,
}
impl<A, S: ArchiveStorage> OwnedArchive<A, S>
where
A: for<'a> rkyv::CheckBytes<rkyv::validation::validators::DefaultValidator<'a>>,
{
pub fn new(storage: S, pos: usize) -> error_stack::Result<Self, DeserializationError> {
let bytes = &*storage;
if let Err(e) = rkyv::check_archived_value::<FakeArchive<A>>(bytes, pos) {
let err = error_stack::Report::new(DeserializationError).attach_printable(e.to_string());
return Err(err);
}
Ok(Self {
storage,
pos,
_marker: PhantomData,
})
}
}
impl<A, S: ArchiveStorage> Clone for OwnedArchive<A, S>
where
S: Clone,
{
fn clone(&self) -> Self {
Self {
storage: self.storage.clone(),
pos: self.pos,
_marker: PhantomData,
}
}
}
impl<A, S: ArchiveStorage> ops::Deref for OwnedArchive<A, S> {
type Target = A;
fn deref(&self) -> &Self::Target {
let bytes = &*self.storage;
// SAFETY: We have already checked that the bytes are valid for the given type in the constructor
unsafe { rkyv::archived_value::<FakeArchive<A>>(bytes, self.pos) }
}
}
/// # Safety
/// This trait is unsafe to implement for the following reasons:
/// - The implementor must ensure that calling [ops::Deref::deref] on the implementor
/// returns the same slice every time (i.e. the slice is not moved, altered, or reallocated).
/// - The implementor must ensure that calling [ops::Deref::deref] returns bytes with
/// correct aligment for the archived data.
/// - The implementor must ensure that calling [Clone::clone] produces a clone that uphlods
/// the previous two invariants. This does not mean that the clone cannot copy the bytes,
/// but it must copy them in a way that upholds the previous invariants.
pub unsafe trait ArchiveStorage: ops::Deref<Target = [u8]> + Sized {}
unsafe impl ArchiveStorage for Box<[u8]> {}
unsafe impl ArchiveStorage for Arc<[u8]> {}
#[derive(Debug, thiserror::Error)]
#[error("deserialization failed")]
pub struct DeserializationError;
struct FakeArchive<A> {
_marker: PhantomData<A>,
}
impl<A> rkyv::Archive for FakeArchive<A> {
type Archived = A;
type Resolver = ();
unsafe fn resolve(&self, _pos: usize, _resolver: Self::Resolver, _out: *mut Self::Archived) {
unreachable!()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment