use core::convert::Infallible;
use crate::{Patch, emitter::Pos};
pub unsafe trait Flat: Sized {
#[doc(hidden)]
const _ASSERT_NO_DROP: () = ();
unsafe fn deep_copy(&self, p: &mut impl Patch, at: Pos);
fn validate(addr: usize, buf: &[u8]) -> Result<(), crate::ValidateError>;
fn validate_option(addr: usize, buf: &[u8]) -> Result<(), crate::ValidateError> {
crate::ValidateError::check::<Option<Self>>(addr, buf)
}
}
macro_rules! impl_flat {
($($ty:ty),*) => {
$(
unsafe impl Flat for $ty {
unsafe fn deep_copy(&self, p: &mut impl Patch, at: Pos) {
unsafe { p.write_flat(at, *self) };
}
fn validate(addr: usize, buf: &[u8]) -> Result<(), crate::ValidateError> {
crate::ValidateError::check::<Self>(addr, buf)
}
}
)*
};
}
impl_flat!(u8, u16, u32, i32, u64, i64);
unsafe impl Flat for bool {
unsafe fn deep_copy(&self, p: &mut impl Patch, at: Pos) {
unsafe { p.write_flat(at, *self) };
}
fn validate(addr: usize, buf: &[u8]) -> Result<(), crate::ValidateError> {
crate::ValidateError::check::<Self>(addr, buf)?;
let value = buf[addr];
if value > 1 {
return Err(crate::ValidateError::InvalidBool { addr, value });
}
Ok(())
}
}
unsafe impl Flat for Infallible {
unsafe fn deep_copy(&self, _p: &mut impl Patch, _at: Pos) {
match *self {}
}
fn validate(_addr: usize, _buf: &[u8]) -> Result<(), crate::ValidateError> {
Err(crate::ValidateError::Uninhabited)
}
}
unsafe impl<A: Flat, B: Flat> Flat for (A, B) {
unsafe fn deep_copy(&self, p: &mut impl Patch, at: Pos) {
unsafe {
self.0.deep_copy(p, at.offset(core::mem::offset_of!((A, B), 0)));
self.1.deep_copy(p, at.offset(core::mem::offset_of!((A, B), 1)));
}
}
fn validate(addr: usize, buf: &[u8]) -> Result<(), crate::ValidateError> {
crate::ValidateError::check::<Self>(addr, buf)?;
A::validate(addr + core::mem::offset_of!((A, B), 0), buf)?;
B::validate(addr + core::mem::offset_of!((A, B), 1), buf)?;
Ok(())
}
}
unsafe impl<T: Flat, const N: usize> Flat for [T; N] {
unsafe fn deep_copy(&self, p: &mut impl Patch, at: Pos) {
for (i, elem) in self.iter().enumerate() {
unsafe { elem.deep_copy(p, at.offset(i * size_of::<T>())) };
}
}
fn validate(addr: usize, buf: &[u8]) -> Result<(), crate::ValidateError> {
crate::ValidateError::check::<Self>(addr, buf)?;
for i in 0..N {
T::validate(addr + i * size_of::<T>(), buf)?;
}
Ok(())
}
}
unsafe impl<T: Flat> Flat for Option<T> {
unsafe fn deep_copy(&self, p: &mut impl Patch, at: Pos) {
unsafe {
p.write_bytes(at, core::ptr::from_ref(self).cast(), size_of::<Self>());
}
if let Some(val) = self {
let inner_offset = (core::ptr::from_ref(val) as usize) - (core::ptr::from_ref(self) as usize);
unsafe { val.deep_copy(p, at.offset(inner_offset)) };
}
}
fn validate(addr: usize, buf: &[u8]) -> Result<(), crate::ValidateError> {
T::validate_option(addr, buf)
}
}