Skip to content

Instantly share code, notes, and snippets.

@MaxOhn
Created September 2, 2023 02:30
Show Gist options
  • Save MaxOhn/f5e2ea72f745f7c9ddec7d4963a6042d to your computer and use it in GitHub Desktop.
Save MaxOhn/f5e2ea72f745f7c9ddec7d4963a6042d to your computer and use it in GitHub Desktop.
Archiving by using a wrapper that converts types into something archivable
mod with_convert;
use rkyv::with::DeserializeWith;
use rkyv::{Archive, Archived, Deserialize, Fallible, Serialize};
use tracing::Level;
use self::with_convert::{ToArchivable, WithConvert};
fn main() {
let my_struct = MyStruct { level: Level::WARN };
let bytes = rkyv::to_bytes::<_, 0>(&my_struct).unwrap();
let archived = unsafe { rkyv::archived_root::<MyStruct>(&bytes) };
println!("Archived level: {}", archived.level);
struct MyDeserializer;
impl Fallible for MyDeserializer {
type Error = LevelDeserializeError;
}
let deserialized: MyStruct = archived.deserialize(&mut MyDeserializer).unwrap();
println!("Deserialized level: {}", deserialized.level);
}
#[derive(Archive, Deserialize, Serialize)]
pub struct MyStruct {
#[with(WithConvert<WithLevel>)]
level: Level,
}
pub struct WithLevel;
impl ToArchivable<Level> for WithLevel {
type Archivable = u8;
fn to_archivable(level: &Level) -> Self::Archivable {
match *level {
Level::TRACE => 0,
Level::DEBUG => 1,
Level::INFO => 2,
Level::WARN => 3,
Level::ERROR => 4,
}
}
}
#[derive(Debug)]
pub struct LevelDeserializeError {
pub level: u8,
}
impl<D: Fallible + ?Sized> DeserializeWith<u8, Level, D> for WithLevel
where
D::Error: From<LevelDeserializeError>,
{
fn deserialize_with(
archived: &Archived<u8>,
_deserialize: &mut D,
) -> Result<Level, <D as Fallible>::Error> {
match *archived {
0 => Ok(Level::TRACE),
1 => Ok(Level::DEBUG),
2 => Ok(Level::INFO),
3 => Ok(Level::WARN),
4 => Ok(Level::ERROR),
level => Err(LevelDeserializeError { level }.into()),
}
}
}
use std::marker::PhantomData;
use rkyv::{
with::{ArchiveWith, DeserializeWith, SerializeWith},
Archive, Archived, Fallible, Resolver, Serialize,
};
/// Convert a reference of one type to a type that implements [`Archive`].
pub trait ToArchivable<O> {
type Archivable: Archive;
fn to_archivable(original: &O) -> Self::Archivable;
}
/// Convert a reference of one type to a type that implements [`Serialize`].
pub trait ToSerializable<O, S: Fallible + ?Sized>: ToArchivable<O>
where
Self::Archivable: Serialize<S>,
{
}
// Implemented automatically for all applicable types
impl<T, O, S> ToSerializable<O, S> for T
where
S: Fallible + ?Sized,
T: ToArchivable<O>,
T::Archivable: Serialize<S>,
{
}
/// Enable types that implement [`ToArchivable`], [`ToSerializable`], and [`DeserializeWith`] to be
/// used as `with` wrapper.
pub struct WithConvert<U>(PhantomData<U>);
impl<U, O> ArchiveWith<O> for WithConvert<U>
where
U: ToArchivable<O>,
{
type Archived = Archived<U::Archivable>;
type Resolver = Resolver<U::Archivable>;
unsafe fn resolve_with(
field: &O,
pos: usize,
resolver: Self::Resolver,
out: *mut Self::Archived,
) {
U::to_archivable(field).resolve(pos, resolver, out);
}
}
impl<U, O, S> SerializeWith<O, S> for WithConvert<U>
where
S: Fallible,
U: ToSerializable<O, S>,
U::Archivable: Serialize<S>,
{
fn serialize_with(
field: &O,
serializer: &mut S,
) -> Result<Self::Resolver, <S as Fallible>::Error> {
U::to_archivable(field).serialize(serializer)
}
}
impl<D, U, O> DeserializeWith<Archived<U::Archivable>, O, D> for WithConvert<U>
where
D: Fallible + ?Sized,
U: ToArchivable<O> + DeserializeWith<Archived<U::Archivable>, O, D>,
{
fn deserialize_with(
field: &Archived<U::Archivable>,
deserializer: &mut D,
) -> Result<O, <D as Fallible>::Error> {
U::deserialize_with(field, deserializer)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment