use core::{cmp::Ordering, iter::FusedIterator, marker::PhantomData, num::NonZeroUsize};
use typenum::marker_traits::Unsigned;
#[repr(transparent)]
pub struct WOVolAddress<T> {
address: NonZeroUsize,
marker: PhantomData<*mut T>,
}
impl<T> Clone for WOVolAddress<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for WOVolAddress<T> {}
impl<T> PartialEq for WOVolAddress<T> {
fn eq(&self, other: &Self) -> bool {
self.address == other.address
}
}
impl<T> Eq for WOVolAddress<T> {}
impl<T> PartialOrd for WOVolAddress<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.address.cmp(&other.address))
}
}
impl<T> Ord for WOVolAddress<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.address.cmp(&other.address)
}
}
impl<T> core::fmt::Debug for WOVolAddress<T> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "WOVolAddress({:p})", *self)
}
}
impl<T> core::fmt::Pointer for WOVolAddress<T> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{:p}", self.address.get() as *mut T)
}
}
impl<T> WOVolAddress<T> {
pub const unsafe fn new(address: usize) -> Self {
Self {
address: NonZeroUsize::new_unchecked(address),
marker: PhantomData,
}
}
pub const unsafe fn cast<Z>(self) -> WOVolAddress<Z> {
WOVolAddress {
address: self.address,
marker: PhantomData,
}
}
pub const unsafe fn offset(self, offset: isize) -> Self {
Self {
address: NonZeroUsize::new_unchecked(self.address.get().wrapping_add(offset as usize * core::mem::size_of::<T>())),
marker: PhantomData,
}
}
pub const fn is_aligned(self) -> bool {
self.address.get() % core::mem::align_of::<T>() == 0
}
pub const fn to_usize(self) -> usize {
self.address.get()
}
pub const unsafe fn iter_slots(self, slots: usize) -> WOVolIter<T> {
WOVolIter {
vol_address: self,
slots_remaining: slots,
}
}
pub fn write(self, val: T) {
unsafe { (self.address.get() as *mut T).write_volatile(val) }
}
}
pub struct WOVolBlock<T, C: Unsigned> {
vol_address: WOVolAddress<T>,
slot_count: PhantomData<C>,
}
impl<T, C: Unsigned> Clone for WOVolBlock<T, C> {
fn clone(&self) -> Self {
*self
}
}
impl<T, C: Unsigned> Copy for WOVolBlock<T, C> {}
impl<T, C: Unsigned> PartialEq for WOVolBlock<T, C> {
fn eq(&self, other: &Self) -> bool {
self.vol_address == other.vol_address
}
}
impl<T, C: Unsigned> Eq for WOVolBlock<T, C> {}
impl<T, C: Unsigned> core::fmt::Debug for WOVolBlock<T, C> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "WOVolBlock({:p}, count={})", self.vol_address.address.get() as *mut T, C::USIZE)
}
}
impl<T, C: Unsigned> WOVolBlock<T, C> {
pub const unsafe fn new(address: usize) -> Self {
Self {
vol_address: WOVolAddress::new(address),
slot_count: PhantomData,
}
}
pub const fn len(self) -> usize {
C::USIZE
}
pub const fn iter(self) -> WOVolIter<T> {
WOVolIter {
vol_address: self.vol_address,
slots_remaining: C::USIZE,
}
}
pub const unsafe fn index_unchecked(self, slot: usize) -> WOVolAddress<T> {
self.vol_address.offset(slot as isize)
}
pub fn index(self, slot: usize) -> WOVolAddress<T> {
if slot < C::USIZE {
unsafe { self.index_unchecked(slot) }
} else {
panic!("Index Requested: {} >= Slot Count: {}", slot, C::USIZE)
}
}
pub fn get(self, slot: usize) -> Option<WOVolAddress<T>> {
if slot < C::USIZE {
unsafe { Some(self.index_unchecked(slot)) }
} else {
None
}
}
}
pub struct WOVolSeries<T, C: Unsigned, S: Unsigned> {
vol_address: WOVolAddress<T>,
slot_count: PhantomData<C>,
stride: PhantomData<S>,
}
impl<T, C: Unsigned, S: Unsigned> Clone for WOVolSeries<T, C, S> {
fn clone(&self) -> Self {
*self
}
}
impl<T, C: Unsigned, S: Unsigned> Copy for WOVolSeries<T, C, S> {}
impl<T, C: Unsigned, S: Unsigned> PartialEq for WOVolSeries<T, C, S> {
fn eq(&self, other: &Self) -> bool {
self.vol_address == other.vol_address
}
}
impl<T, C: Unsigned, S: Unsigned> Eq for WOVolSeries<T, C, S> {}
impl<T, C: Unsigned, S: Unsigned> core::fmt::Debug for WOVolSeries<T, C, S> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(
f,
"WOVolSeries({:p}, count={}, series={})",
self.vol_address.address.get() as *mut T,
C::USIZE,
S::USIZE
)
}
}
impl<T, C: Unsigned, S: Unsigned> WOVolSeries<T, C, S> {
pub const unsafe fn new(address: usize) -> Self {
Self {
vol_address: WOVolAddress::new(address),
slot_count: PhantomData,
stride: PhantomData,
}
}
pub const fn len(self) -> usize {
C::USIZE
}
pub const fn iter(self) -> WOVolStridingIter<T, S> {
WOVolStridingIter {
vol_address: self.vol_address,
slots_remaining: C::USIZE,
stride: PhantomData,
}
}
pub const unsafe fn index_unchecked(self, slot: usize) -> WOVolAddress<T> {
self.vol_address.cast::<u8>().offset((S::USIZE * slot) as isize).cast::<T>()
}
pub fn index(self, slot: usize) -> WOVolAddress<T> {
if slot < C::USIZE {
unsafe { self.index_unchecked(slot) }
} else {
panic!("Index Requested: {} >= Slot Count: {}", slot, C::USIZE)
}
}
pub fn get(self, slot: usize) -> Option<WOVolAddress<T>> {
if slot < C::USIZE {
unsafe { Some(self.index_unchecked(slot)) }
} else {
None
}
}
}
pub struct WOVolIter<T> {
vol_address: WOVolAddress<T>,
slots_remaining: usize,
}
impl<T> Clone for WOVolIter<T> {
fn clone(&self) -> Self {
Self {
vol_address: self.vol_address,
slots_remaining: self.slots_remaining,
}
}
}
impl<T> PartialEq for WOVolIter<T> {
fn eq(&self, other: &Self) -> bool {
self.vol_address == other.vol_address && self.slots_remaining == other.slots_remaining
}
}
impl<T> Eq for WOVolIter<T> {}
impl<T> Iterator for WOVolIter<T> {
type Item = WOVolAddress<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.slots_remaining > 0 {
let out = self.vol_address;
unsafe {
self.slots_remaining -= 1;
self.vol_address = self.vol_address.offset(1);
}
Some(out)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.slots_remaining, Some(self.slots_remaining))
}
fn count(self) -> usize {
self.slots_remaining
}
fn last(self) -> Option<Self::Item> {
if self.slots_remaining > 0 {
Some(unsafe { self.vol_address.offset(self.slots_remaining as isize) })
} else {
None
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
if self.slots_remaining > n {
unsafe {
let out = self.vol_address.offset(n as isize);
let jump = n + 1;
self.slots_remaining -= jump;
self.vol_address = self.vol_address.offset(jump as isize);
Some(out)
}
} else {
self.slots_remaining = 0;
None
}
}
fn max(self) -> Option<Self::Item> {
self.last()
}
fn min(mut self) -> Option<Self::Item> {
self.nth(0)
}
}
impl<T> FusedIterator for WOVolIter<T> {}
impl<T> core::fmt::Debug for WOVolIter<T> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(
f,
"WOVolIter({:p}, remaining={})",
self.vol_address.address.get() as *mut T,
self.slots_remaining
)
}
}
pub struct WOVolStridingIter<T, S: Unsigned> {
vol_address: WOVolAddress<T>,
slots_remaining: usize,
stride: PhantomData<S>,
}
impl<T, S: Unsigned> Clone for WOVolStridingIter<T, S> {
fn clone(&self) -> Self {
Self {
vol_address: self.vol_address,
slots_remaining: self.slots_remaining,
stride: PhantomData,
}
}
}
impl<T, S: Unsigned> PartialEq for WOVolStridingIter<T, S> {
fn eq(&self, other: &Self) -> bool {
self.vol_address == other.vol_address && self.slots_remaining == other.slots_remaining
}
}
impl<T, S: Unsigned> Eq for WOVolStridingIter<T, S> {}
impl<T, S: Unsigned> Iterator for WOVolStridingIter<T, S> {
type Item = WOVolAddress<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.slots_remaining > 0 {
let out = self.vol_address;
unsafe {
self.slots_remaining -= 1;
self.vol_address = self.vol_address.cast::<u8>().offset(S::ISIZE).cast::<T>();
}
Some(out)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.slots_remaining, Some(self.slots_remaining))
}
fn count(self) -> usize {
self.slots_remaining
}
fn last(self) -> Option<Self::Item> {
if self.slots_remaining > 0 {
Some(unsafe {
self
.vol_address
.cast::<u8>()
.offset(S::ISIZE * (self.slots_remaining as isize))
.cast::<T>()
})
} else {
None
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
if self.slots_remaining > n {
unsafe {
let out = self.vol_address.cast::<u8>().offset(S::ISIZE * (n as isize)).cast::<T>();
let jump = n + 1;
self.slots_remaining -= jump;
self.vol_address = self.vol_address.cast::<u8>().offset(S::ISIZE * (jump as isize)).cast::<T>();
Some(out)
}
} else {
self.slots_remaining = 0;
None
}
}
fn max(self) -> Option<Self::Item> {
self.last()
}
fn min(mut self) -> Option<Self::Item> {
self.nth(0)
}
}
impl<T, S: Unsigned> FusedIterator for WOVolStridingIter<T, S> {}
impl<T, S: Unsigned> core::fmt::Debug for WOVolStridingIter<T, S> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(
f,
"WOVolStridingIter({:p}, remaining={}, stride={})",
self.vol_address.address.get() as *mut T,
self.slots_remaining,
S::USIZE
)
}
}