use {
crate::{
error::Error,
mapper::Mapper,
marker::{self, AccessorTypeSpecifier, Readable, Writable},
},
core::{fmt, hash::Hash, marker::PhantomData, mem, ptr},
};
#[deprecated(since = "0.3.2", note = "Use `ReadWrite`.")]
pub type Array<T, M> = ReadWrite<T, M>;
pub type ReadWrite<T, M> = Generic<T, M, marker::ReadWrite>;
pub type ReadOnly<T, M> = Generic<T, M, marker::ReadOnly>;
pub type WriteOnly<T, M> = Generic<T, M, marker::WriteOnly>;
pub struct Generic<T, M, A>
where
M: Mapper,
A: AccessorTypeSpecifier,
{
virt: usize,
len: usize,
_marker: PhantomData<T>,
_read_write: PhantomData<A>,
mapper: M,
}
#[allow(clippy::len_without_is_empty)] impl<T, M, A> Generic<T, M, A>
where
M: Mapper,
A: AccessorTypeSpecifier,
{
pub unsafe fn new(phys_base: usize, len: usize, mut mapper: M) -> Self {
assert!(super::is_aligned::<T>(phys_base));
assert_ne!(len, 0);
let bytes = mem::size_of::<T>() * len;
let virt = mapper.map(phys_base, bytes).get();
Self {
virt,
len,
_marker: PhantomData,
_read_write: PhantomData,
mapper,
}
}
pub unsafe fn try_new(phys_base: usize, len: usize, mapper: M) -> Result<Self, Error> {
if len == 0 {
Err(Error::EmptyArray)
} else if super::is_aligned::<T>(phys_base) {
Ok(Self::new(phys_base, len, mapper))
} else {
Err(Error::NotAligned {
alignment: mem::align_of::<T>(),
address: phys_base,
})
}
}
pub fn len(&self) -> usize {
self.len
}
fn addr(&self, i: usize) -> usize {
self.virt + mem::size_of::<T>() * i
}
fn bytes(&self) -> usize {
mem::size_of::<T>() * self.len
}
}
impl<T, M, A> Generic<T, M, A>
where
M: Mapper,
A: Readable,
{
pub fn read_volatile_at(&self, i: usize) -> T {
assert!(i < self.len());
unsafe { ptr::read_volatile(self.addr(i) as *const _) }
}
#[deprecated(since = "0.3.1", note = "use `read_volatile_at`")]
pub fn read_at(&self, i: usize) -> T {
self.read_volatile_at(i)
}
}
impl<T, M, A> Generic<T, M, A>
where
M: Mapper,
A: Writable,
{
pub fn write_volatile_at(&mut self, i: usize, v: T) {
assert!(i < self.len());
unsafe {
ptr::write_volatile(self.addr(i) as *mut _, v);
}
}
#[deprecated(since = "0.3.1", note = "use `write_volatile_at`")]
pub fn write_at(&mut self, i: usize, v: T) {
self.write_volatile_at(i, v);
}
}
impl<T, M, A> Generic<T, M, A>
where
M: Mapper,
A: Readable + Writable,
{
pub fn update_volatile_at<U>(&mut self, i: usize, f: U)
where
U: FnOnce(&mut T),
{
let mut v = self.read_volatile_at(i);
f(&mut v);
self.write_volatile_at(i, v);
}
#[deprecated(since = "0.3.1", note = "use `update_volatile_at`")]
pub fn update_at<U>(&mut self, i: usize, f: U)
where
U: FnOnce(&mut T),
{
self.update_volatile_at(i, f);
}
}
impl<T, M, A> fmt::Debug for Generic<T, M, A>
where
T: fmt::Debug,
M: Mapper,
A: Readable,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self).finish()
}
}
impl<T, M, A> PartialEq for Generic<T, M, A>
where
T: PartialEq,
M: Mapper,
A: Readable,
{
fn eq(&self, other: &Self) -> bool {
self.into_iter()
.zip(other.into_iter())
.map(|(a, b)| a.eq(&b))
.all(|x| x)
}
}
impl<T, M, A> Eq for Generic<T, M, A>
where
T: Eq,
M: Mapper,
A: Readable,
{
}
impl<T, M, A> Hash for Generic<T, M, A>
where
T: Hash,
M: Mapper,
A: Readable,
{
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
for e in self {
e.hash(state);
}
}
}
impl<'a, T, M, A> IntoIterator for &'a Generic<T, M, A>
where
M: Mapper,
A: Readable,
{
type Item = T;
type IntoIter = Iter<'a, T, M, A>;
fn into_iter(self) -> Self::IntoIter {
Iter::new(self)
}
}
impl<T, M, A> Drop for Generic<T, M, A>
where
M: Mapper,
A: AccessorTypeSpecifier,
{
fn drop(&mut self) {
self.mapper.unmap(self.virt, self.bytes());
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct Iter<'a, T, M, A>
where
M: Mapper,
A: Readable,
{
a: &'a Generic<T, M, A>,
i: usize,
}
impl<'a, T, M, A> Iter<'a, T, M, A>
where
M: Mapper,
A: Readable,
{
fn new(a: &'a Generic<T, M, A>) -> Self {
Self { a, i: 0 }
}
}
impl<'a, T, M, A> Iterator for Iter<'a, T, M, A>
where
M: Mapper,
A: Readable,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.i < self.a.len() {
let t = self.a.read_volatile_at(self.i);
self.i += 1;
Some(t)
} else {
None
}
}
}