#[cfg(feature = "alloc")]
mod alloc;
mod core;
#[cfg(feature = "std")]
mod std;
use ::core::mem;
use rancor::{Fallible, Strategy};
pub use self::core::*;
#[cfg(feature = "std")]
pub use self::std::*;
use crate::{Archive, ArchiveUnsized, Place, RelPtr};
pub trait Positional {
fn pos(&self) -> usize;
}
impl<'a, T> Positional for &'a T
where
T: Positional + ?Sized,
{
fn pos(&self) -> usize {
T::pos(*self)
}
}
impl<'a, T> Positional for &'a mut T
where
T: Positional + ?Sized,
{
fn pos(&self) -> usize {
T::pos(*self)
}
}
impl<T, E> Positional for Strategy<T, E>
where
T: Positional + ?Sized,
{
fn pos(&self) -> usize {
T::pos(self)
}
}
pub trait Writer<E = <Self as Fallible>::Error>: Positional {
fn write(&mut self, bytes: &[u8]) -> Result<(), E>;
}
impl<'a, T, E> Writer<E> for &'a mut T
where
T: Writer<E> + ?Sized,
{
fn write(&mut self, bytes: &[u8]) -> Result<(), E> {
T::write(*self, bytes)
}
}
impl<T, E> Writer<E> for Strategy<T, E>
where
T: Writer<E> + ?Sized,
{
fn write(&mut self, bytes: &[u8]) -> Result<(), E> {
T::write(self, bytes)
}
}
pub trait WriterExt<E>: Writer<E> {
fn pad(&mut self, padding: usize) -> Result<(), E> {
const MAX_ZEROES: usize = 32;
const ZEROES: [u8; MAX_ZEROES] = [0; MAX_ZEROES];
debug_assert!(padding < MAX_ZEROES);
self.write(&ZEROES[0..padding])
}
fn align(&mut self, align: usize) -> Result<usize, E> {
let mask = align - 1;
debug_assert_eq!(align & mask, 0);
self.pad((align - (self.pos() & mask)) & mask)?;
Ok(self.pos())
}
fn align_for<T>(&mut self) -> Result<usize, E> {
self.align(mem::align_of::<T>())
}
unsafe fn resolve_aligned<T: Archive + ?Sized>(
&mut self,
value: &T,
resolver: T::Resolver,
) -> Result<usize, E> {
let pos = self.pos();
debug_assert_eq!(pos & (mem::align_of::<T::Archived>() - 1), 0);
let mut resolved = mem::MaybeUninit::<T::Archived>::zeroed();
let out = unsafe { Place::new_unchecked(pos, resolved.as_mut_ptr()) };
value.resolve(resolver, out);
self.write(out.as_slice())?;
Ok(pos)
}
unsafe fn resolve_unsized_aligned<T: ArchiveUnsized + ?Sized>(
&mut self,
value: &T,
to: usize,
) -> Result<usize, E> {
let from = self.pos();
debug_assert_eq!(
from & (mem::align_of::<RelPtr<T::Archived>>() - 1),
0
);
let mut resolved = mem::MaybeUninit::<RelPtr<T::Archived>>::zeroed();
let out = unsafe { Place::new_unchecked(from, resolved.as_mut_ptr()) };
RelPtr::emplace_unsized(to, value.archived_metadata(), out);
self.write(out.as_slice())?;
Ok(from)
}
}
impl<T, E> WriterExt<E> for T where T: Writer<E> + ?Sized {}
#[cfg(test)]
mod tests {
#[cfg(feature = "alloc")]
#[test]
fn reusable_writer() {
use rend::{u16_le, u32_le};
use crate::{api::high::to_bytes_in, util::AlignedVec};
let mut writer = AlignedVec::<16>::new();
_ = to_bytes_in::<_, rancor::Error>(
&u32_le::from_native(42),
&mut writer,
);
assert_eq!(&writer[..], &[42, 0, 0, 0]);
writer.clear();
_ = to_bytes_in::<_, rancor::Error>(
&u16_le::from_native(1337),
&mut writer,
);
assert_eq!(&writer[..], &[57, 5]);
writer.clear();
assert_eq!(writer.capacity(), 4);
}
}