use core::marker::PhantomData;
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MemLoc<const ADDR: usize, const SIZE: usize>;
impl<const ADDR: usize, const SIZE: usize> MemLoc<ADDR, SIZE> {
pub const fn new() -> Self {
Self
}
pub const fn addr(&self) -> usize {
ADDR
}
pub const fn size(&self) -> usize {
SIZE
}
pub const fn range(&self) -> core::ops::Range<usize> {
ADDR..ADDR + SIZE
}
}
pub trait MemLocType<const ADDR: usize, const SIZE: usize> {
type Type;
const ADDR: usize = ADDR;
const SIZE: usize = SIZE;
const LOC: MemLoc<ADDR, SIZE> = MemLoc::new();
fn layout(loc: MemLoc<ADDR, SIZE>) -> LayoutType<ADDR, SIZE, Self> {
LayoutType(loc, PhantomData)
}
}
pub struct LayoutType<const ADDR: usize, const SIZE: usize, T>(MemLoc<ADDR, SIZE>, PhantomData<T>)
where
T: MemLocType<ADDR, SIZE> + ?Sized;
impl<const ADDR: usize, const SIZE: usize, T> LayoutType<ADDR, SIZE, T>
where
T: MemLocType<ADDR, SIZE>,
{
pub const fn new() -> Self {
Self(MemLoc::new(), PhantomData)
}
pub const fn loc(&self) -> MemLoc<ADDR, SIZE> {
self.0
}
}
pub trait MemLayout {
type Type;
const LAYOUT: Self::Type;
const LEN: usize;
}
#[macro_export]
macro_rules! mem_layout {
() => {};
(@accum () -> ($s:ident for $o:ident $($f:ident: $t:ty = $si:expr, $a:expr);*) -> ($($addr:tt)*)) => {
mem_layout!(@as_expr ($s $o $($f, $si, $t, $a)*) -> ($($addr)*));
};
(@accum ($field:ident: $t:ty = $size:expr, $($tail:tt)*) -> ($s:ident for $o:ident $($f:ident: $typ:ty = $si:expr, $a:expr);*) -> ($($addr:tt)*)) => {
mem_layout!(@accum ($($tail)*) -> ($s for $o $($f: $typ = $si, $a);*; $field: $t = $size, $($addr)*) -> ($($addr)* + $size ));
};
(@as_expr ($s:ident $o:ident $($field:ident, $size:expr, $t:ty, $addr:expr)+) -> ($($len:tt)*)) => {
#[derive(Debug, Default)]
#[allow(missing_docs)]
pub struct $s {
$(pub $field: $crate::MemLoc<{$addr}, $size>,)+
}
impl $s {
#[allow(missing_docs)]
pub const fn new() -> Self {
Self {
$($field: $crate::MemLoc::new(),)+
}
}
#[allow(missing_docs)]
pub const LEN: usize = $($len)*;
}
impl $crate::MemLayout for $o {
type Type = $s;
const LAYOUT: Self::Type = $s::new();
const LEN: usize = Self::Type::LEN;
}
$(
impl $crate::MemLocType<{ <$o as $crate::MemLayout>::LAYOUT.$field.addr() }, { <$o as $crate::MemLayout>::LAYOUT.$field.size() }> for $o {
type Type = $t;
}
)+
};
($s:ident for $o:ident $field:ident: $t:ty = $size:expr, $($tail:tt)*) => {
mem_layout!(@accum ($($tail)*,) -> ($s for $o $field: $t = $size, 0) -> (0 + $size));
};
}