use std::{fmt::Debug, marker::PhantomData, mem::MaybeUninit}; use rancor::{Fallible, Panic, ResultExt, Source, Strategy}; use rkyv::{ api::low::LowSerializer, ser::{allocator::SubAllocator, writer::Buffer, Writer}, with::{ArchiveWith, DeserializeWith, Map, SerializeWith}, Archive, Archived, Deserialize, Place, Resolver, Serialize, }; type ArchivedWith = >::Archived; fn roundtrip(remote: &T) where F: ArchiveWith + for<'a, 'b> SerializeWith> + DeserializeWith, T, Strategy<(), Panic>>, T: Debug + PartialEq, { let mut bytes = [0_u8; 128]; let buf = serialize::(remote, &mut bytes); let archived = access::(&buf); let deserialized: T = F::deserialize_with(archived, Strategy::wrap(&mut ())).always_ok(); assert_eq!(remote, &deserialized); } #[test] fn named_struct() { #[derive(Debug, PartialEq)] struct Remote<'a, A> { a: u8, b: PhantomData<&'a A>, c: Option, } #[derive(Archive, Serialize, Deserialize)] #[rkyv(remote = Remote<'a, A>)] struct Example<'a, A> { a: u8, #[rkyv(with = Identity)] b: PhantomData<&'a A>, #[rkyv(with = Map)] c: Option, } impl<'a, A> From> for Remote<'a, A> { fn from(value: Example<'a, A>) -> Self { Remote { a: value.a, b: value.b, c: value.c, } } } #[derive(Archive, Serialize, Deserialize)] #[rkyv(remote = Remote<'a, A>)] struct Partial<'a, A> { b: PhantomData<&'a A>, #[rkyv(with = Map)] c: Option, } impl<'a, A> From> for Remote<'a, A> { fn from(archived: Partial<'a, A>) -> Self { Self { a: 42, b: archived.b, c: archived.c, } } } let remote = Remote { a: 42, b: PhantomData, c: Some(Foo::default()), }; roundtrip::, _>(&remote); roundtrip::, _>(&remote); } #[test] fn unnamed_struct() { #[derive(Debug, PartialEq)] struct Remote<'a, A>(u8, PhantomData<&'a A>, Option); #[derive(Archive, Serialize, Deserialize)] #[rkyv(remote = Remote::<'a, A>)] struct Example<'a, A>( u8, #[rkyv(with = Identity)] PhantomData<&'a A>, #[rkyv(with = Map)] Option, ); impl<'a, A> From> for Remote<'a, A> { fn from(value: Example<'a, A>) -> Self { Remote(value.0, value.1, value.2) } } #[derive(Archive, Serialize, Deserialize)] #[rkyv(remote = Remote::<'a, A>)] struct Partial<'a, A>( u8, #[rkyv(with = Identity)] PhantomData<&'a A>, // Only trailing fields may be omitted for unnamed structs ); impl<'a, A> From> for Remote<'a, A> { fn from(archived: Partial<'a, A>) -> Self { Remote(archived.0, archived.1, Some(Foo::default())) } } let remote = Remote(42, PhantomData, Some(Foo::default())); roundtrip::, _>(&remote); roundtrip::, _>(&remote); } #[test] fn unit_struct() { #[derive(Debug, PartialEq)] struct Remote; #[derive(Archive, Serialize, Deserialize)] #[rkyv(remote = Remote)] struct Example; impl From for Remote { fn from(_: Example) -> Self { Self } } let remote = Remote; roundtrip::(&remote); } #[test] fn full_enum() { #[derive(Debug, PartialEq)] enum Remote<'a, A> { A, B(u8), C { a: PhantomData<&'a A>, b: Option, }, } #[derive(Archive, Serialize, Deserialize)] #[rkyv(remote = Remote::<'a, A>)] enum Example<'a, A> { A, B(u8), C { #[rkyv(with = Identity)] a: PhantomData<&'a A>, #[rkyv(with = Map)] b: Option, }, } impl<'a, A> From> for Remote<'a, A> { fn from(value: Example<'a, A>) -> Self { match value { Example::A => Remote::A, Example::B(value) => Remote::B(value), Example::C { a, b } => Remote::C { a, b }, } } } #[derive(Archive, Serialize, Deserialize)] #[rkyv(remote = Remote::<'a, A>)] // If a variant is missing (or the remote type is `#[non_exhaustive]`), one // *unit* variant must be denoted with `#[rkyv(other)]`. enum Partial<'a, A> { A, C { a: PhantomData<&'a A>, }, #[rkyv(other)] Other, } impl<'a, A> From> for Remote<'a, A> { fn from(archived: Partial<'a, A>) -> Self { match archived { Partial::A => Remote::A, Partial::C { a } => Remote::C { a, b: Some(Foo::default()), }, Partial::Other => Remote::B(42), } } } for remote in [ Remote::A, Remote::B(42), Remote::C { a: PhantomData, b: Some(Foo::default()), }, ] { roundtrip::, _>(&remote); roundtrip::, _>(&remote); } } #[test] fn named_struct_private() { mod remote { #[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct Remote { inner: [u8; 4], } impl Remote { pub fn new(inner: [u8; 4]) -> Self { Self { inner } } pub fn inner(&self) -> [u8; 4] { self.inner } pub fn inner_ref(&self) -> &[u8; 4] { &self.inner } } } #[derive(Archive, Serialize, Deserialize)] #[rkyv(remote = remote::Remote)] struct ExampleByRef { #[rkyv(getter = remote::Remote::inner)] inner: [u8; 4], } impl From for remote::Remote { fn from(value: ExampleByRef) -> Self { remote::Remote::new(value.inner) } } #[derive(Archive, Serialize, Deserialize)] #[rkyv(remote = remote::Remote)] struct ExampleThroughRef { #[rkyv(getter = remote::Remote::inner_ref)] inner: [u8; 4], } impl From for remote::Remote { fn from(value: ExampleThroughRef) -> Self { remote::Remote::new(value.inner) } } let remote = remote::Remote::default(); roundtrip::(&remote); roundtrip::(&remote); } #[test] fn unnamed_struct_private() { mod remote { #[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct Remote([u8; 4]); impl Remote { pub fn new(inner: [u8; 4]) -> Self { Self(inner) } pub fn inner(&self) -> [u8; 4] { self.0 } pub fn inner_ref(&self) -> &[u8; 4] { &self.0 } } } #[derive(Archive, Serialize, Deserialize)] #[rkyv(remote = remote::Remote)] struct ExampleByRef(#[rkyv(getter = remote::Remote::inner)] [u8; 4]); impl From for remote::Remote { fn from(value: ExampleByRef) -> Self { remote::Remote::new(value.0) } } #[derive(Archive, Serialize, Deserialize)] #[rkyv(remote = remote::Remote)] struct ExampleThroughRef( #[rkyv(getter = remote::Remote::inner_ref)] [u8; 4], ); impl From for remote::Remote { fn from(value: ExampleThroughRef) -> Self { remote::Remote::new(value.0) } } let remote = remote::Remote::default(); roundtrip::(&remote); roundtrip::(&remote); } #[cfg(feature = "bytecheck")] pub trait CheckedArchived: for<'a> rkyv::bytecheck::CheckBytes> { } #[cfg(feature = "bytecheck")] impl< Archived: for<'a> rkyv::bytecheck::CheckBytes< rkyv::api::low::LowValidator<'a, Panic>, >, > CheckedArchived for Archived { } #[cfg(not(feature = "bytecheck"))] pub trait CheckedArchived {} #[cfg(not(feature = "bytecheck"))] impl CheckedArchived for Archived {} type Serializer<'a, 'b> = LowSerializer, SubAllocator<'a>, Panic>; fn serialize<'buf, F, T>(remote: &T, buf: &'buf mut [u8; 128]) -> Buffer<'buf> where F: for<'a, 'b> SerializeWith>, { struct Wrap<'a, F, T>(&'a T, PhantomData); impl Archive for Wrap<'_, F, T> where F: ArchiveWith, { type Archived = >::Archived; type Resolver = >::Resolver; fn resolve( &self, resolver: Self::Resolver, out: Place, ) { F::resolve_with(self.0, resolver, out) } } impl<'a, 'b, F, T> Serialize> for Wrap<'_, F, T> where F: SerializeWith>, { fn serialize( &self, serializer: &mut Serializer<'a, 'b>, ) -> Result { F::serialize_with(self.0, serializer) } } let wrap = Wrap(remote, PhantomData::); let writer = Buffer::from(buf); let mut scratch = [MaybeUninit::uninit(); 128]; let alloc = SubAllocator::new(&mut scratch); rkyv::api::low::to_bytes_in_with_alloc::<_, _, Panic>(&wrap, writer, alloc) .always_ok() } fn access(bytes: &[u8]) -> &>::Archived where F: ArchiveWith, { #[cfg(feature = "bytecheck")] { rkyv::api::low::access::<>::Archived, Panic>(bytes) .always_ok() } #[cfg(not(feature = "bytecheck"))] unsafe { rkyv::access_unchecked::<>::Archived>(bytes) } } #[derive(Debug, PartialEq)] struct Foo([u8; 4]); impl Default for Foo { fn default() -> Self { Self([2, 3, 5, 7]) } } struct FooWrap; impl ArchiveWith for FooWrap { type Archived = Archived<[u8; 4]>; type Resolver = Resolver<[u8; 4]>; fn resolve_with( field: &Foo, resolver: Self::Resolver, out: Place, ) { field.0.resolve(resolver, out); } } impl SerializeWith for FooWrap where S: Fallible + Writer + ?Sized, { fn serialize_with( field: &Foo, serializer: &mut S, ) -> Result { field.0.serialize(serializer) } } impl DeserializeWith, Foo, D> for FooWrap { fn deserialize_with( archived: &Archived<[u8; 4]>, deserializer: &mut D, ) -> Result { archived.deserialize(deserializer).map(Foo) } } struct Identity; impl ArchiveWith for Identity { type Archived = Archived; type Resolver = Resolver; fn resolve_with( this: &T, resolver: Self::Resolver, out: Place, ) { this.resolve(resolver, out); } } impl> SerializeWith for Identity { fn serialize_with( this: &T, serializer: &mut S, ) -> Result::Error> { this.serialize(serializer) } } impl DeserializeWith, T, D> for Identity where D: Fallible + ?Sized, T: Archive, Archived: Deserialize, { fn deserialize_with( archived: &Archived, deserializer: &mut D, ) -> Result::Error> { archived.deserialize(deserializer) } }