use core::{fmt, intrinsics, marker::PhantomData, ops::{Deref, DerefMut, Index, IndexMut, Range, RangeBounds}, ptr, slice::{range, SliceIndex}};
pub trait CanRead {}
pub trait CanWrite {}
#[derive(Debug, Copy, Clone)]
pub struct ReadWrite;
impl CanRead for ReadWrite {}
impl CanWrite for ReadWrite {}
#[derive(Debug, Copy, Clone)]
pub struct Read;
impl CanRead for Read {}
#[derive(Debug, Copy, Clone)]
pub struct Write;
impl CanWrite for Write {}
#[derive(Clone)]
#[repr(transparent)]
pub struct VOL<R, A = ReadWrite>
{
access: PhantomData<A>,
reference: R,
}
impl<R> VOL<R>
{
pub const fn new(reference: R) -> VOL<R>
{
VOL
{
access: PhantomData,
reference,
}
}
pub const fn new_ro(reference: R) -> VOL<R, Read>
{
VOL
{
access: PhantomData,
reference,
}
}
pub const fn new_wo(reference: R) -> VOL<R, Write>
{
VOL
{
access: PhantomData,
reference,
}
}
}
impl<R, T, A> VOL<R, A>
where
R: Deref<Target = T>,
T: Copy,
{
pub fn read(&self) -> T
where
A: CanRead,
{
unsafe
{
ptr::read_volatile(&*self.reference)
}
}
pub fn write(&mut self, value: T)
where
A: CanWrite,
R: DerefMut,
{
unsafe
{
ptr::write_volatile(&mut *self.reference, value)
};
}
pub fn update<F>(&mut self, f: F)
where
A: CanRead + CanWrite,
R: DerefMut,
F: FnOnce(&mut T),
{
let mut value = self.read();
f(&mut value);
self.write(value);
}
}
impl<R, A> VOL<R, A>
{
pub fn extract_inner(self) -> R
{
self.reference
}
}
impl<R, T, A> VOL<R, A>
where
R: Deref<Target = T>,
T: ?Sized,
{
pub fn map<'a, F, U>(&'a self, f: F) -> VOL<&'a U, A>
where
F: FnOnce(&'a T) -> &'a U,
U: ?Sized,
T: 'a,
{
VOL
{
access: self.access,
reference: f(self.reference.deref()),
}
}
pub fn mapmut<'a, F, U>(&'a mut self, f: F) -> VOL<&'a mut U, A>
where
F: FnOnce(&mut T) -> &mut U,
R: DerefMut,
U: ?Sized,
T: 'a,
{
VOL
{
access: self.access,
reference: f(&mut self.reference),
}
}
}
impl<T, R, A> VOL<R, A>
where
R: Deref<Target = [T]>,
{
pub fn idx<'a, I>(&'a self, idx: I) -> VOL<&'a I::Output, A>
where
I: SliceIndex<[T]>,
T: 'a,
{
self.map(|slice| slice.index(idx))
}
pub fn idxmut<'a, I>(&'a mut self, idx: I) -> VOL<&mut I::Output, A>
where
I: SliceIndex<[T]>,
R: DerefMut,
T: 'a,
{
self.mapmut(|slice| slice.index_mut(idx))
}
pub fn cp_into_slice(&self, dst: &mut [T])
where
T: Copy,
{
assert_eq!(self.reference.len(), dst.len(), "DEST/SRC SLICES HAVE DIFFERING LENGTHS");
unsafe
{
intrinsics::volatile_copy_nonoverlapping_memory(dst.as_mut_ptr(), self.reference.as_ptr(), self.reference.len());
}
}
pub fn cp_from_slice(&mut self, src: &[T])
where
T: Copy,
R: DerefMut,
{
assert_eq!(self.reference.len(), src.len(), "DEST/SRC SLICES HAVE DIFFERING LENGTHS");
unsafe
{
intrinsics::volatile_copy_nonoverlapping_memory(self.reference.as_mut_ptr(), src.as_ptr(), self.reference.len());
}
}
pub fn cpinternal(&mut self, src: impl RangeBounds<usize>, dest: usize)
where
T: Copy,
R: DerefMut,
{
let Range
{
start: src_start,
end: src_end,
} = range(src, ..self.reference.len());
let count = src_end - src_start;
assert!(dest <= self.reference.len() - count, "DESTINATION OUT OF BOUNDS");
unsafe
{
intrinsics::volatile_copy_memory(self.reference.as_mut_ptr().add(dest), self.reference.as_ptr().add(src_start), count);
}
}
}
impl<R, A> VOL<R, A>
where
R: Deref<Target = [u8]>,
{
pub fn fill(&mut self, value: u8)
where
R: DerefMut,
{
unsafe
{
intrinsics::volatile_set_memory(self.reference.as_mut_ptr(), value, self.reference.len());
}
}
}
impl<R, A, T, const N: usize> VOL<R, A>
where
R: Deref<Target = [T; N]>,
{
pub fn as_slice(&self) -> VOL<&[T], A>
{
self.map(|array| &array[..])
}
pub fn as_mut_slice(&mut self) -> VOL<&mut [T], A>
where
R: DerefMut,
{
self.mapmut(|array| &mut array[..])
}
}
impl<R> VOL<R>
{
pub fn ro(self) -> VOL<R, Read>
{
VOL
{
access: PhantomData,
reference: self.reference,
}
}
pub fn wo(self) -> VOL<R, Write>
{
VOL
{
access: PhantomData,
reference: self.reference,
}
}
}
impl<R, T, A> fmt::Debug for VOL<R, A>
where
R: Deref<Target = T>,
T: Copy + fmt::Debug,
A: CanRead,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
f.debug_tuple("VOL").field(&self.read()).finish()
}
}
impl<R> fmt::Debug for VOL<R, Write>
where
R: Deref,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
f.debug_tuple("VOL").field(&"[WO]").finish()
}
}