use crate::Memory;
#[derive(Clone, Debug, Default)]
pub struct LocalMember<T> {
offsets: Vec<usize>,
_phantom: std::marker::PhantomData<*mut T>,
}
impl<T: Sized + Copy> LocalMember<T> {
#[must_use]
pub fn new() -> Self {
Self {
offsets: Vec::new(),
_phantom: std::marker::PhantomData,
}
}
#[must_use]
pub fn new_offset(offsets: Vec<usize>) -> Self {
Self {
offsets,
_phantom: std::marker::PhantomData,
}
}
}
impl<T: Sized + Copy> Memory<T> for LocalMember<T> {
fn set_offset(&mut self, new_offsets: Vec<usize>) {
self.offsets = new_offsets;
}
fn get_offset(&self) -> std::io::Result<usize> {
let mut offset = 0_usize;
for i in 0..self.offsets.len() - 1 {
offset = offset.wrapping_add(self.offsets[i]);
if offset == 0 {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Would be a null dereference!",
));
}
unsafe {
offset = (offset as *const usize).read_unaligned();
}
}
Ok(offset.wrapping_add(self.offsets[self.offsets.len() - 1]))
}
unsafe fn read(&self) -> std::io::Result<T> {
let offset = self.get_offset()? as *const T;
let x: T = offset.read_unaligned();
Ok(x)
}
fn write(&self, value: &T) -> std::io::Result<()> {
use std::ptr::copy_nonoverlapping;
let offset = self.get_offset()? as *mut T;
unsafe {
copy_nonoverlapping(value, offset, 1_usize);
}
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn modify_local_i32() {
let test = 4_i32;
let mut member = LocalMember::<i32>::new();
member.set_offset(vec![std::ptr::addr_of!(test) as usize]);
unsafe {
assert_eq!(test, member.read().unwrap());
}
member.write(&5_i32).unwrap();
assert_eq!(test, 5_i32);
}
#[test]
fn modify_local_i64() {
let test = 3_i64;
let mut member = LocalMember::<i64>::new();
member.set_offset(vec![std::ptr::addr_of!(test) as usize]);
unsafe {
assert_eq!(test, member.read().unwrap());
}
member.write(&-1_i64).unwrap();
assert_eq!(test, -1);
}
#[test]
fn modify_local_usize() {
let test = 0_usize;
let mut member = LocalMember::<usize>::new();
member.set_offset(vec![std::ptr::addr_of!(test) as usize]);
unsafe {
assert_eq!(test, member.read().unwrap());
}
member.write(&0xffff).unwrap();
assert_eq!(test, 0xffff);
}
}