use super::*;
#[repr(C)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct VolRegion<T, R, W> {
pub(crate) addr: VolAddress<T, R, W>,
pub(crate) len: usize,
}
impl<T, R, W> Clone for VolRegion<T, R, W> {
#[inline]
#[must_use]
fn clone(&self) -> Self {
*self
}
}
impl<T, R, W> Copy for VolRegion<T, R, W> {}
impl<T, R, W> core::fmt::Debug for VolRegion<T, R, W> {
#[cold]
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "VolRegion<{elem_ty}, r{readability}, w{writeability}>({address:#X}, len: {len})",
elem_ty = core::any::type_name::<T>(),
readability=core::any::type_name::<R>(),
writeability=core::any::type_name::<W>(),
address=self.addr.as_usize(),
len=self.len,
)
}
}
impl<T, R, W, const C: usize> From<VolBlock<T, R, W, C>>
for VolRegion<T, R, W>
{
#[inline]
#[must_use]
fn from(block: VolBlock<T, R, W, C>) -> Self {
Self { addr: block.base, len: C }
}
}
impl<T, R, W> VolRegion<T, R, W> {
#[inline]
#[must_use]
pub const unsafe fn from_raw_parts(
addr: VolAddress<T, R, W>, len: usize,
) -> Self {
Self { addr, len }
}
#[inline]
#[must_use]
pub const fn len(self) -> usize {
self.len
}
#[inline]
#[must_use]
pub const fn as_usize(self) -> usize {
self.addr.address.get()
}
#[inline]
#[must_use]
pub const fn as_ptr(self) -> *const T {
self.addr.address.get() as *const T
}
#[inline]
#[must_use]
pub const fn as_mut_ptr(self) -> *mut T {
self.addr.address.get() as *mut T
}
#[inline]
#[must_use]
pub fn as_slice_ptr(self) -> *const [T] {
core::ptr::slice_from_raw_parts(
self.addr.address.get() as *const T,
self.len,
)
}
#[inline]
#[must_use]
pub fn as_slice_mut_ptr(self) -> *mut [T] {
core::ptr::slice_from_raw_parts_mut(
self.addr.address.get() as *mut T,
self.len,
)
}
#[inline]
#[must_use]
#[track_caller]
pub const fn index(self, i: usize) -> VolAddress<T, R, W> {
if i < self.len {
unsafe { self.addr.add(i) }
} else {
#[allow(unconditional_panic)]
unsafe {
VolAddress::new([usize::MAX][1])
}
}
}
#[inline]
#[must_use]
pub const fn get(self, i: usize) -> Option<VolAddress<T, R, W>> {
if i < self.len {
Some(unsafe { self.addr.add(i) })
} else {
None
}
}
#[inline]
#[must_use]
#[track_caller]
pub fn sub_slice<RB: core::ops::RangeBounds<usize>>(self, r: RB) -> Self {
use core::ops::Bound;
let start_inclusive: usize = match r.start_bound() {
Bound::Included(i) => *i,
Bound::Excluded(x) => x + 1,
Bound::Unbounded => 0,
};
assert!(start_inclusive < self.len);
let end_exclusive: usize = match r.end_bound() {
Bound::Included(i) => i + 1,
Bound::Excluded(x) => *x,
Bound::Unbounded => self.len,
};
assert!(end_exclusive <= self.len);
let len = end_exclusive.saturating_sub(start_inclusive);
Self { addr: unsafe { self.addr.add(start_inclusive) }, len }
}
#[inline]
#[must_use]
pub const fn iter(self) -> VolBlockIter<T, R, W> {
VolBlockIter { base: self.addr, count: self.len }
}
#[inline]
#[must_use]
#[track_caller]
pub fn iter_range<RB: core::ops::RangeBounds<usize>>(
self, r: RB,
) -> VolBlockIter<T, R, W> {
self.sub_slice(r).iter()
}
}
impl<T, W> VolRegion<T, Safe, W>
where
T: Copy,
{
#[inline]
pub fn read_to_slice(self, buffer: &mut [T]) {
assert_eq!(self.len, buffer.len());
self.iter().zip(buffer.iter_mut()).for_each(|(va, s)| *s = va.read())
}
}
impl<T, W> VolRegion<T, Unsafe, W>
where
T: Copy,
{
#[inline]
pub unsafe fn read_to_slice(self, buffer: &mut [T]) {
assert_eq!(self.len, buffer.len());
self.iter().zip(buffer.iter_mut()).for_each(|(va, s)| *s = va.read())
}
}
impl<T, R> VolRegion<T, R, Safe>
where
T: Copy,
{
#[inline]
pub fn write_from_slice(self, buffer: &[T]) {
assert_eq!(self.len, buffer.len());
self.iter().zip(buffer.iter()).for_each(|(va, s)| va.write(*s))
}
}
impl<T, R> VolRegion<T, R, Unsafe>
where
T: Copy,
{
#[inline]
pub unsafe fn write_from_slice(self, buffer: &[T]) {
assert_eq!(self.len, buffer.len());
self.iter().zip(buffer.iter()).for_each(|(va, s)| va.write(*s))
}
}
#[test]
fn test_volregion_sub_slice() {
let region: VolRegion<u8, Unsafe, Unsafe> =
unsafe { VolRegion::from_raw_parts(VolAddress::new(1), 10) };
assert_eq!(region.len, 10);
let sub_region = region.sub_slice(..);
assert_eq!(sub_region.len, 10);
let sub_region = region.sub_slice(2..);
assert_eq!(sub_region.len, 10 - 2);
let sub_region = region.sub_slice(..3);
assert_eq!(sub_region.len, 3);
let sub_region = region.sub_slice(4..6);
assert_eq!(sub_region.len, 2);
}