Created
September 2, 2023 02:30
-
-
Save MaxOhn/f5e2ea72f745f7c9ddec7d4963a6042d to your computer and use it in GitHub Desktop.
Archiving by using a wrapper that converts types into something archivable
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
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()), | |
} | |
} | |
} |
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; | |
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