#![no_std]
#![warn(rust_2018_idioms)]
#![warn(missing_docs)]
#![warn(clippy::all)]
use core::slice::SliceIndex;
pub trait MemoryStorage {
type Error: core::fmt::Debug;
fn get<I>(&self, index: I) -> Result<&I::Output, Self::Error>
where
I: SliceIndex<[u8]>;
fn get_mut<I>(&mut self, index: I) -> Result<&mut I::Output, Self::Error>
where
I: SliceIndex<[u8]>;
fn try_read_byte(&self, addr: usize) -> Result<u8, Self::Error>;
fn try_write_byte(&mut self, addr: usize, byte: u8) -> Result<(), Self::Error>;
fn read_byte(&self, addr: usize) -> u8 {
self.try_read_byte(addr)
.expect("failed to read from memory")
}
fn write_byte(&mut self, addr: usize, byte: u8) {
self.try_write_byte(addr, byte)
.expect("failed to write to memory")
}
fn try_read<V: Value>(&self, addr: usize) -> Result<V, Self::Error> {
let size = core::mem::size_of::<V>();
let slice = self.get(addr..addr + size)?;
let value = unsafe {
debug_assert_eq!(core::mem::size_of::<V>(), slice.len());
let slice = core::slice::from_raw_parts(slice.as_ptr() as *const V, 1);
slice[0].to_le()
};
Ok(value)
}
fn read<V: Value>(&self, addr: usize) -> V {
self.try_read::<V>(addr).expect("failed to read memory")
}
fn try_read_be<V: Value>(&self, addr: usize) -> Result<V, Self::Error> {
self.try_read(addr).map(Value::to_be)
}
fn read_be<V: Value>(&self, addr: usize) -> V {
self.read::<V>(addr).to_be()
}
fn try_write<V: Value>(&mut self, addr: usize, val: V) -> Result<(), Self::Error> {
let size = core::mem::size_of::<V>();
let val = val.to_le();
let slice = self.get_mut(addr..addr + size)?;
let raw_value = unsafe {
let ptr: *const V = &val;
core::slice::from_raw_parts(ptr as *const u8, size)
};
slice.copy_from_slice(raw_value);
Ok(())
}
fn write<V: Value>(&mut self, addr: usize, val: V) {
self.try_write::<V>(addr, val)
.expect("failed to write memory")
}
fn try_write_be<V: Value>(&mut self, addr: usize, val: V) -> Result<(), Self::Error> {
self.try_write(addr, val.to_be())
}
fn write_be<V: Value>(&mut self, addr: usize, val: V) {
self.write(addr, val.to_be());
}
}
macro_rules! impl_trait {
($($ty:path),*) => {
$(
impl Value for $ty {
fn to_le(self) -> Self {
self.to_le()
}
fn to_be(self) -> Self {
self.to_be()
}
}
)*
};
}
pub trait Value: private::Sealed + Sized + Copy {
fn to_le(self) -> Self;
fn to_be(self) -> Self;
}
impl_trait!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128);
mod private {
pub trait Sealed {}
macro_rules! impl_trait {
($($ty:path),*) => {
$(impl Sealed for $ty {})*
};
}
impl_trait!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128);
}