Created
February 9, 2024 16:24
-
-
Save Alxandr/b6ce7547ba0d097801211b575f34fa04 to your computer and use it in GitHub Desktop.
Owned archive (rkyv)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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