mod macros;
use core::{fmt, marker::PhantomData, num::NonZeroUsize};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Lit<T>(VolAddr<T>);
impl<T> Lit<T> {
pub fn new(addr: VolAddr<T>) -> Self {
Self(addr)
}
pub const fn size() -> usize {
core::mem::size_of::<T>()
}
pub fn addr(self) -> VolAddr<T> {
self.0
}
pub fn read(self) -> T
where
T: Copy,
{
self.0.read()
}
#[inline]
pub unsafe fn read_non_copy(self) -> T {
self.0.read_non_copy()
}
#[inline]
pub fn write(self, val: T) {
self.0.write(val);
}
}
#[repr(transparent)]
pub struct VolAddr<T> {
addr: NonZeroUsize,
_type: PhantomData<*mut T>,
}
impl<T> VolAddr<T> {
pub const unsafe fn new(addr: usize) -> Self {
Self {
addr: NonZeroUsize::new_unchecked(addr),
_type: PhantomData,
}
}
pub const unsafe fn cast<U>(self) -> VolAddr<U> {
VolAddr {
addr: self.addr,
_type: PhantomData,
}
}
pub const unsafe fn offset(self, offset: isize) -> Self {
Self {
addr: NonZeroUsize::new_unchecked(
self.addr
.get()
.wrapping_add(offset as usize * core::mem::size_of::<T>()),
),
_type: PhantomData,
}
}
#[inline]
pub fn read(self) -> T
where
T: Copy,
{
unsafe { core::ptr::read_volatile(self.addr.get() as *mut T) }
}
#[inline]
pub unsafe fn read_non_copy(self) -> T {
core::ptr::read_volatile(self.addr.get() as *mut T)
}
#[inline]
pub fn write(self, val: T) {
unsafe { core::ptr::write_volatile(self.addr.get() as *mut T, val) }
}
}
impl<T> Clone for VolAddr<T> {
fn clone(&self) -> Self {
Self {
addr: self.addr,
_type: PhantomData,
}
}
}
impl<T> Copy for VolAddr<T> {}
impl<T> fmt::Debug for VolAddr<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "VolAddr({:p})", self)
}
}
impl<T> fmt::Pointer for VolAddr<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:p}", self.addr.get() as *mut T)
}
}
impl<T> PartialEq for VolAddr<T> {
fn eq(&self, other: &Self) -> bool {
self.addr == other.addr
}
}
impl<T> Eq for VolAddr<T> {}
impl<T> PartialOrd for VolAddr<T> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.addr.partial_cmp(&other.addr)
}
}
impl<T> Ord for VolAddr<T> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.addr.cmp(&other.addr)
}
}