use super::*;
#[repr(transparent)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct VolAddress<T, R, W> {
pub(crate) address: NonZeroUsize,
target: PhantomData<T>,
read_status: PhantomData<R>,
write_status: PhantomData<W>,
}
impl<T, R, W> Clone for VolAddress<T, R, W> {
#[inline]
#[must_use]
fn clone(&self) -> Self {
*self
}
}
impl<T, R, W> Copy for VolAddress<T, R, W> {}
impl<T, R, W> VolAddress<T, R, W> {
#[inline]
#[must_use]
pub const unsafe fn new(address: usize) -> Self {
Self {
address: NonZeroUsize::new_unchecked(address),
target: PhantomData,
read_status: PhantomData,
write_status: PhantomData,
}
}
#[inline]
#[must_use]
pub const unsafe fn cast<Z>(self) -> VolAddress<Z, R, W> {
VolAddress {
address: self.address,
target: PhantomData,
read_status: PhantomData,
write_status: PhantomData,
}
}
#[inline]
#[must_use]
pub const unsafe fn change_permissions<NewRead, NewWrite>(
self,
) -> VolAddress<T, NewRead, NewWrite> {
VolAddress {
address: self.address,
target: PhantomData,
read_status: PhantomData,
write_status: PhantomData,
}
}
#[inline]
#[must_use]
pub const fn as_usize(self) -> usize {
self.address.get()
}
#[inline]
#[must_use]
pub const fn as_ptr(self) -> *const T {
self.address.get() as *const T
}
#[inline]
#[must_use]
pub const fn as_mut_ptr(self) -> *mut T {
self.address.get() as *mut T
}
#[inline]
#[must_use]
pub const unsafe fn add(self, count: usize) -> Self {
self.offset(count as isize)
}
#[inline]
#[must_use]
pub const unsafe fn sub(self, count: usize) -> Self {
self.offset((count as isize).wrapping_neg())
}
#[inline]
#[must_use]
pub const unsafe fn offset(self, count: isize) -> Self {
let total_delta = core::mem::size_of::<T>().wrapping_mul(count as usize);
VolAddress {
address: NonZeroUsize::new_unchecked(
self.address.get().wrapping_add(total_delta),
),
target: PhantomData,
read_status: PhantomData,
write_status: PhantomData,
}
}
}
impl<T, R, W, const C: usize> VolAddress<[T; C], R, W> {
#[inline]
#[must_use]
pub const unsafe fn as_volblock(self) -> VolBlock<T, R, W, C> {
VolBlock { base: self.cast::<T>() }
}
}
impl<T, W> VolAddress<T, Safe, W>
where
T: Copy,
{
#[inline]
pub fn read(self) -> T {
unsafe { read_volatile(self.address.get() as *const T) }
}
}
impl<T, W> VolAddress<T, Unsafe, W>
where
T: Copy,
{
#[inline]
pub unsafe fn read(self) -> T {
read_volatile(self.address.get() as *const T)
}
}
impl<T, R> VolAddress<T, R, Safe>
where
T: Copy,
{
#[inline]
pub fn write(self, t: T) {
unsafe { write_volatile(self.address.get() as *mut T, t) }
}
}
impl<T, R> VolAddress<T, R, Unsafe>
where
T: Copy,
{
#[inline]
pub unsafe fn write(self, t: T) {
write_volatile(self.address.get() as *mut T, t)
}
}
impl<T> VolAddress<T, Safe, Safe>
where
T: Copy,
{
#[inline]
pub fn apply<F: FnOnce(&mut T)>(self, op: F) {
let mut temp = self.read();
op(&mut temp);
self.write(temp);
}
}
impl<T> VolAddress<T, Unsafe, Safe>
where
T: Copy,
{
#[inline]
pub unsafe fn apply<F: FnOnce(&mut T)>(self, op: F) {
let mut temp = self.read();
op(&mut temp);
self.write(temp);
}
}
impl<T> VolAddress<T, Safe, Unsafe>
where
T: Copy,
{
#[inline]
pub unsafe fn apply<F: FnOnce(&mut T)>(self, op: F) {
let mut temp = self.read();
op(&mut temp);
self.write(temp);
}
}
impl<T> VolAddress<T, Unsafe, Unsafe>
where
T: Copy,
{
#[inline]
pub unsafe fn apply<F: FnOnce(&mut T)>(self, op: F) {
let mut temp = self.read();
op(&mut temp);
self.write(temp);
}
}
impl<T, R, W> core::fmt::Debug for VolAddress<T, R, W> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(
f,
"VolAddress<{elem_ty}, r{readability}, w{writeability}>(0x{address:#X})",
elem_ty = core::any::type_name::<T>(),
readability = core::any::type_name::<R>(),
writeability = core::any::type_name::<W>(),
address = self.address.get()
)
}
}
impl<T, R, W> core::fmt::Pointer for VolAddress<T, R, W> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "0x{address:#X}", address = self.address.get())
}
}