use core::{fmt, marker::PhantomData, num::NonZero, ops::Deref};
use crate::{Flat, Patch, emitter::Pos};
pub struct Near<T> {
off: NonZero<i32>,
_type: PhantomData<T>,
}
unsafe impl<T: Flat> Flat for Near<T> {
unsafe fn deep_copy(&self, p: &mut impl Patch, at: Pos) {
let target = p.alloc::<T>();
unsafe {
self.get().deep_copy(p, target);
p.patch_near::<T>(at, target);
}
}
fn validate(addr: usize, buf: &[u8]) -> Result<(), crate::ValidateError> {
crate::ValidateError::check::<Self>(addr, buf)?;
let off = i32::from_ne_bytes(buf[addr..addr + 4].try_into().unwrap());
if off == 0 {
return Err(crate::ValidateError::NullNear { addr });
}
let target = addr.cast_signed().wrapping_add(off as isize).cast_unsigned();
crate::ValidateError::check::<T>(target, buf)?;
T::validate(target, buf)
}
fn validate_option(addr: usize, buf: &[u8]) -> Result<(), crate::ValidateError> {
crate::ValidateError::check::<i32>(addr, buf)?;
let off = i32::from_ne_bytes(buf[addr..addr + 4].try_into().unwrap());
if off == 0 {
return Ok(()); }
let target = addr.cast_signed().wrapping_add(off as isize).cast_unsigned();
crate::ValidateError::check::<T>(target, buf)?;
T::validate(target, buf)
}
}
impl<T: Flat> Near<T> {
#[must_use]
pub fn get(&self) -> &T {
unsafe {
let base = core::ptr::from_ref(&self.off).cast::<u8>();
let target = base.addr().wrapping_add_signed(self.off.get() as isize);
&*core::ptr::with_exposed_provenance::<T>(target)
}
}
}
impl<T: Flat> Deref for Near<T> {
type Target = T;
fn deref(&self) -> &T {
self.get()
}
}
impl<T: Flat + PartialEq> PartialEq for Near<T> {
fn eq(&self, other: &Self) -> bool {
*self.get() == *other.get()
}
}
impl<T: Flat + Eq> Eq for Near<T> {}
impl<T: Flat + fmt::Debug> fmt::Debug for Near<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.get(), f)
}
}
impl<T: Flat + fmt::Display> fmt::Display for Near<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.get(), f)
}
}