raw_struct/
memory.rs

1use core::{
2    self,
3    convert::Infallible,
4    mem::{
5        self,
6        MaybeUninit,
7    },
8    slice,
9};
10
11use crate::{
12    error::OutOfBoundsViolation,
13    MemoryDecodeError,
14};
15
16pub trait MemoryView {
17    type AccessError;
18
19    fn read_memory(&self, offset: u64, buffer: &mut [u8]) -> Result<(), Self::AccessError>;
20}
21
22impl<M: MemoryView> MemoryView for &M {
23    type AccessError = M::AccessError;
24
25    fn read_memory(&self, offset: u64, buffer: &mut [u8]) -> Result<(), Self::AccessError> {
26        M::read_memory(self, offset, buffer)
27    }
28}
29
30#[cfg(feature = "alloc")]
31impl<M: ?Sized + MemoryView> MemoryView for alloc::sync::Arc<M> {
32    type AccessError = M::AccessError;
33
34    fn read_memory(&self, offset: u64, buffer: &mut [u8]) -> Result<(), Self::AccessError> {
35        M::read_memory(self, offset, buffer)
36    }
37}
38
39impl MemoryView for &[u8] {
40    type AccessError = OutOfBoundsViolation;
41
42    fn read_memory(&self, offset: u64, buffer: &mut [u8]) -> Result<(), Self::AccessError> {
43        let offset = offset as usize;
44        if offset + buffer.len() > self.len() {
45            return Err(OutOfBoundsViolation {
46                access_offset: offset,
47                access_len: buffer.len(),
48
49                src_len: self.len(),
50            });
51        }
52
53        buffer.copy_from_slice(&self[offset..offset + buffer.len()]);
54        Ok(())
55    }
56}
57
58pub trait MemoryViewDereferenceable: MemoryView {
59    fn dereference(&self, address: u64) -> Result<u64, Self::AccessError>;
60}
61
62impl<M: MemoryViewDereferenceable> MemoryViewDereferenceable for &M {
63    fn dereference(&self, address: u64) -> Result<u64, Self::AccessError> {
64        M::dereference(&self, address)
65    }
66}
67
68#[cfg(feature = "alloc")]
69impl<M: ?Sized + MemoryViewDereferenceable> MemoryViewDereferenceable for alloc::sync::Arc<M> {
70    fn dereference(&self, address: u64) -> Result<u64, Self::AccessError> {
71        M::dereference(&self, address)
72    }
73}
74
75/// Decode an object from memory view.
76///
77/// Note:
78/// The decoded object may be different in memory representation and size then the original.
79pub trait FromMemoryView: Sized {
80    type DecodeError;
81
82    fn read_object<M: MemoryView>(
83        view: &M,
84        offset: u64,
85    ) -> Result<Self, MemoryDecodeError<M::AccessError, Self::DecodeError>>;
86
87    // fn read_boxed(view: &dyn MemoryView, offset: u64) -> Result<Box<Self>, Box<dyn error::ErrorType>>;
88}
89
90/// Marker trait for types that can be trivially constructed by copying their
91/// underlying data. It can also be assumed, that the size of a CopyConstructable is the actual binary object size.
92///
93/// For types implementing this trait:
94/// - [`FromMemoryView`] is automatically implemented.
95/// - The associated [`DecodeError`] is fixed to [`Infallible`], since decoding
96///   cannot fail.
97pub trait CopyConstructable: Copy {}
98
99impl<T: CopyConstructable> FromMemoryView for T {
100    type DecodeError = Infallible;
101
102    fn read_object<M: MemoryView>(
103        view: &M,
104        offset: u64,
105    ) -> Result<Self, MemoryDecodeError<M::AccessError, Self::DecodeError>> {
106        let mut result = MaybeUninit::uninit();
107
108        let result_memory = unsafe {
109            slice::from_raw_parts_mut(result.as_mut_ptr() as *mut u8, mem::size_of::<T>())
110        };
111
112        view.read_memory(offset, result_memory)
113            .map_err(MemoryDecodeError::MemoryAccess)?;
114
115        Ok(unsafe { result.assume_init() })
116    }
117}
118
119impl<T1: CopyConstructable, T2: CopyConstructable> CopyConstructable for (T1, T2) {}
120impl<T: CopyConstructable, const N: usize> CopyConstructable for [T; N] {}
121
122impl CopyConstructable for u8 {}
123impl CopyConstructable for i8 {}
124
125impl CopyConstructable for u16 {}
126impl CopyConstructable for i16 {}
127
128impl CopyConstructable for u32 {}
129impl CopyConstructable for i32 {}
130
131impl CopyConstructable for u64 {}
132impl CopyConstructable for i64 {}
133
134impl CopyConstructable for f32 {}
135impl CopyConstructable for f64 {}
136
137impl FromMemoryView for bool {
138    type DecodeError = Infallible;
139
140    fn read_object<M: MemoryView>(
141        view: &M,
142        offset: u64,
143    ) -> Result<Self, MemoryDecodeError<M::AccessError, Self::DecodeError>> {
144        let value = u8::read_object(view, offset)?;
145        Ok(value > 0)
146    }
147}
148
149#[cfg(test)]
150mod test {
151    use crate::memory::FromMemoryView;
152
153    #[test]
154    fn test_typing() {
155        let memory = &[0x01u8, 0x00, 0x00, 0x00];
156
157        let x = u32::read_object(&memory.as_slice(), 0x00);
158        assert_eq!(x, Ok(0x01));
159    }
160}