#[cfg(feature = "validation")]
mod validation;
use crate::{ArchivePointee, ArchiveUnsized, Archived};
use core::{
convert::TryFrom,
fmt,
marker::{PhantomData, PhantomPinned},
ptr,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum OffsetError {
IsizeOverflow,
ExceedsStorageRange,
}
impl fmt::Display for OffsetError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
OffsetError::IsizeOverflow => write!(f, "the offset overflowed the range of `isize`"),
OffsetError::ExceedsStorageRange => write!(
f,
"the offset is too far for the offset type of the relative pointer"
),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for OffsetError {}
#[inline]
pub fn signed_offset(from: usize, to: usize) -> Result<isize, OffsetError> {
let (result, overflow) = to.overflowing_sub(from);
if (!overflow && result <= (isize::MAX as usize))
|| (overflow && result >= (isize::MIN as usize))
{
Ok(result as isize)
} else {
Err(OffsetError::IsizeOverflow)
}
}
pub trait Offset: Copy {
fn between(from: usize, to: usize) -> Result<Self, OffsetError>;
fn to_isize(&self) -> isize;
}
macro_rules! impl_offset {
($ty:ty) => {
impl Offset for $ty {
#[inline]
fn between(from: usize, to: usize) -> Result<Self, OffsetError> {
Self::try_from(signed_offset(from, to)?)
.map_err(|_| OffsetError::ExceedsStorageRange)
}
#[inline]
fn to_isize(&self) -> isize {
*self as isize
}
}
};
(@endian $ty:ty) => {
impl Offset for Archived<$ty> {
#[inline]
fn between(from: usize, to: usize) -> Result<Self, OffsetError> {
<$ty>::try_from(signed_offset(from, to)?)
.map(|x| to_archived!(x))
.map_err(|_| OffsetError::ExceedsStorageRange)
}
#[inline]
fn to_isize(&self) -> isize {
from_archived!(*self) as isize
}
}
};
}
impl_offset!(i8);
impl_offset!(@endian i16);
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
impl_offset!(@endian i32);
#[cfg(target_pointer_width = "64")]
impl_offset!(@endian i64);
impl_offset!(u8);
impl_offset!(@endian u16);
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
impl_offset!(@endian u32);
#[cfg(target_pointer_width = "64")]
impl_offset!(@endian u64);
#[derive(Debug)]
pub enum RelPtrError {
OffsetError,
}
#[repr(transparent)]
pub struct RawRelPtr<O> {
offset: O,
_phantom: PhantomPinned,
}
impl<O: Offset> RawRelPtr<O> {
#[inline]
pub unsafe fn try_emplace(from: usize, to: usize, out: *mut Self) -> Result<(), OffsetError> {
let offset = O::between(from, to)?;
ptr::addr_of_mut!((*out).offset).write(offset);
Ok(())
}
#[inline]
pub unsafe fn emplace(from: usize, to: usize, out: *mut Self) {
Self::try_emplace(from, to, out).unwrap();
}
#[inline]
pub fn base(&self) -> *const u8 {
(self as *const Self).cast::<u8>()
}
#[inline]
pub fn base_mut(&mut self) -> *mut u8 {
(self as *mut Self).cast::<u8>()
}
#[inline]
pub fn offset(&self) -> isize {
self.offset.to_isize()
}
#[inline]
pub fn is_null(&self) -> bool {
self.offset() == 0
}
#[inline]
pub fn as_ptr(&self) -> *const () {
unsafe { self.base().offset(self.offset()).cast() }
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut () {
unsafe { self.base_mut().offset(self.offset()).cast() }
}
}
impl<O: fmt::Debug> fmt::Debug for RawRelPtr<O> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RawRelPtr")
.field("offset", &self.offset)
.finish()
}
}
impl<O: Offset> fmt::Pointer for RawRelPtr<O> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.as_ptr(), f)
}
}
pub type RawRelPtrI8 = RawRelPtr<Archived<i8>>;
pub type RawRelPtrI16 = RawRelPtr<Archived<i16>>;
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
pub type RawRelPtrI32 = RawRelPtr<Archived<i32>>;
#[cfg(target_pointer_width = "64")]
pub type RawRelPtrI64 = RawRelPtr<Archived<i64>>;
pub type RawRelPtrU8 = RawRelPtr<Archived<u8>>;
pub type RawRelPtrU16 = RawRelPtr<Archived<u16>>;
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
pub type RawRelPtrU32 = RawRelPtr<Archived<u32>>;
#[cfg(target_pointer_width = "64")]
pub type RawRelPtrU64 = RawRelPtr<Archived<u64>>;
pub struct RelPtr<T: ArchivePointee + ?Sized, O> {
raw_ptr: RawRelPtr<O>,
metadata: T::ArchivedMetadata,
_phantom: PhantomData<T>,
}
impl<T, O: Offset> RelPtr<T, O> {
#[inline]
pub unsafe fn try_emplace(from: usize, to: usize, out: *mut Self) -> Result<(), OffsetError> {
let (fp, fo) = out_field!(out.raw_ptr);
RawRelPtr::try_emplace(from + fp, to, fo)
}
#[inline]
pub unsafe fn emplace(from: usize, to: usize, out: *mut Self) {
Self::try_emplace(from, to, out).unwrap();
}
}
impl<T: ArchivePointee + ?Sized, O: Offset> RelPtr<T, O>
where
T::ArchivedMetadata: Default,
{
#[inline]
pub unsafe fn try_emplace_null(pos: usize, out: *mut Self) -> Result<(), OffsetError> {
let (fp, fo) = out_field!(out.raw_ptr);
RawRelPtr::try_emplace(pos + fp, pos, fo)?;
let (_, fo) = out_field!(out.metadata);
fo.write(Default::default());
Ok(())
}
#[inline]
pub unsafe fn emplace_null(pos: usize, out: *mut Self) {
Self::try_emplace_null(pos, out).unwrap()
}
}
impl<T: ArchivePointee + ?Sized, O: Offset> RelPtr<T, O> {
#[inline]
pub unsafe fn try_resolve_emplace<U: ArchiveUnsized<Archived = T> + ?Sized>(
from: usize,
to: usize,
value: &U,
metadata_resolver: U::MetadataResolver,
out: *mut Self,
) -> Result<(), OffsetError> {
let (fp, fo) = out_field!(out.raw_ptr);
RawRelPtr::try_emplace(from + fp, to, fo)?;
let (fp, fo) = out_field!(out.metadata);
value.resolve_metadata(from + fp, metadata_resolver, fo);
Ok(())
}
#[inline]
pub unsafe fn resolve_emplace<U: ArchiveUnsized<Archived = T> + ?Sized>(
from: usize,
to: usize,
value: &U,
metadata_resolver: U::MetadataResolver,
out: *mut Self,
) {
Self::try_resolve_emplace(from, to, value, metadata_resolver, out).unwrap();
}
#[inline]
pub fn base(&self) -> *const u8 {
self.raw_ptr.base()
}
#[inline]
pub fn base_mut(&mut self) -> *mut u8 {
self.raw_ptr.base_mut()
}
#[inline]
pub fn offset(&self) -> isize {
self.raw_ptr.offset()
}
#[inline]
pub fn is_null(&self) -> bool {
self.raw_ptr.is_null()
}
#[inline]
pub fn metadata(&self) -> &T::ArchivedMetadata {
&self.metadata
}
#[inline]
pub fn as_ptr(&self) -> *const T {
ptr_meta::from_raw_parts(self.raw_ptr.as_ptr(), T::pointer_metadata(&self.metadata))
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut T {
ptr_meta::from_raw_parts_mut(
self.raw_ptr.as_mut_ptr(),
T::pointer_metadata(&self.metadata),
)
}
}
impl<T: ArchivePointee + ?Sized, O: fmt::Debug> fmt::Debug for RelPtr<T, O>
where
T::ArchivedMetadata: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RelPtr")
.field("raw_ptr", &self.raw_ptr)
.field("metadata", &self.metadata)
.finish()
}
}
impl<T: ArchivePointee + ?Sized, O: Offset> fmt::Pointer for RelPtr<T, O> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.as_ptr(), f)
}
}