mod validator;
use core::{alloc::Layout, ops::Range};
use bytecheck::rancor::{Fallible, Source, Strategy};
use rancor::ResultExt as _;
pub use self::validator::*;
use crate::traits::LayoutRaw;
pub unsafe trait ArchiveContext<E = <Self as Fallible>::Error> {
fn check_subtree_ptr(
&mut self,
ptr: *const u8,
layout: &Layout,
) -> Result<(), E>;
unsafe fn push_subtree_range(
&mut self,
root: *const u8,
end: *const u8,
) -> Result<Range<usize>, E>;
unsafe fn pop_subtree_range(
&mut self,
range: Range<usize>,
) -> Result<(), E>;
}
unsafe impl<T, E> ArchiveContext<E> for Strategy<T, E>
where
T: ArchiveContext<E> + ?Sized,
{
fn check_subtree_ptr(
&mut self,
ptr: *const u8,
layout: &Layout,
) -> Result<(), E> {
T::check_subtree_ptr(self, ptr, layout)
}
unsafe fn push_subtree_range(
&mut self,
root: *const u8,
end: *const u8,
) -> Result<Range<usize>, E> {
unsafe { T::push_subtree_range(self, root, end) }
}
unsafe fn pop_subtree_range(
&mut self,
range: Range<usize>,
) -> Result<(), E> {
unsafe { T::pop_subtree_range(self, range) }
}
}
pub trait ArchiveContextExt<E>: ArchiveContext<E> {
fn in_subtree_raw<R>(
&mut self,
ptr: *const u8,
layout: Layout,
f: impl FnOnce(&mut Self) -> Result<R, E>,
) -> Result<R, E>;
fn in_subtree<T: LayoutRaw + ?Sized, R>(
&mut self,
ptr: *const T,
f: impl FnOnce(&mut Self) -> Result<R, E>,
) -> Result<R, E>;
}
impl<C: ArchiveContext<E> + ?Sized, E: Source> ArchiveContextExt<E> for C {
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn in_subtree_raw<R>(
&mut self,
ptr: *const u8,
layout: Layout,
f: impl FnOnce(&mut Self) -> Result<R, E>,
) -> Result<R, E> {
self.check_subtree_ptr(ptr, &layout)?;
let range =
unsafe { self.push_subtree_range(ptr, ptr.add(layout.size()))? };
let result = f(self)?;
unsafe {
self.pop_subtree_range(range)?;
}
Ok(result)
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
fn in_subtree<T: LayoutRaw + ?Sized, R>(
&mut self,
ptr: *const T,
f: impl FnOnce(&mut Self) -> Result<R, E>,
) -> Result<R, E> {
let layout = T::layout_raw(ptr_meta::metadata(ptr)).into_error()?;
let root = ptr as *const u8;
self.in_subtree_raw(root, layout, f)
}
}