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 Single<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,
bytes: usize,
_marker: PhantomData<T>,
_readable_writable: PhantomData<A>,
mapper: M,
}
impl<T, M, A> Generic<T, M, A>
where
M: Mapper,
A: AccessorTypeSpecifier,
{
pub unsafe fn new(phys_base: usize, mut mapper: M) -> Self {
assert!(super::is_aligned::<T>(phys_base));
let bytes = mem::size_of::<T>();
let virt = mapper.map(phys_base, bytes).get();
Self {
virt,
bytes,
_marker: PhantomData,
_readable_writable: PhantomData,
mapper,
}
}
pub unsafe fn try_new(phys_base: usize, mapper: M) -> Result<Self, Error> {
if super::is_aligned::<T>(phys_base) {
Ok(Self::new(phys_base, mapper))
} else {
Err(Error::NotAligned {
alignment: mem::align_of::<T>(),
address: phys_base,
})
}
}
}
impl<T, M, A> Generic<T, M, A>
where
M: Mapper,
A: Readable,
{
pub fn read_volatile(&self) -> T {
unsafe { ptr::read_volatile(self.virt as *const _) }
}
#[deprecated(since = "0.3.1", note = "use `read_volatile`")]
pub fn read(&self) -> T {
self.read_volatile()
}
}
impl<T, M, A> Generic<T, M, A>
where
M: Mapper,
A: Writable,
{
pub fn write_volatile(&mut self, v: T) {
unsafe {
ptr::write_volatile(self.virt as *mut _, v);
}
}
#[deprecated(since = "0.3.1", note = "use `write_volatile`")]
pub fn write(&mut self, v: T) {
self.write_volatile(v);
}
}
impl<T, M, A> Generic<T, M, A>
where
M: Mapper,
A: Readable + Writable,
{
pub fn update_volatile<U>(&mut self, f: U)
where
U: FnOnce(&mut T),
{
let mut v = self.read_volatile();
f(&mut v);
self.write_volatile(v);
}
#[deprecated(since = "0.3.1", note = "use `update_volatile`")]
pub fn update<U>(&mut self, f: U)
where
U: FnOnce(&mut T),
{
self.update_volatile(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 {
write!(f, "{:?}", self.read_volatile())
}
}
impl<T, M, A> PartialEq for Generic<T, M, A>
where
T: PartialEq,
M: Mapper,
A: Readable,
{
fn eq(&self, other: &Self) -> bool {
self.read_volatile().eq(&other.read_volatile())
}
}
impl<T, M, A> Eq for Generic<T, M, A>
where
T: Eq,
M: Mapper,
A: Readable,
{
}
impl<T, M, A> PartialOrd for Generic<T, M, A>
where
T: PartialOrd,
M: Mapper,
A: Readable,
{
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.read_volatile().partial_cmp(&other.read_volatile())
}
}
impl<T, M, A> Ord for Generic<T, M, A>
where
T: Ord,
M: Mapper,
A: Readable,
{
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.read_volatile().cmp(&other.read_volatile())
}
}
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) {
self.read_volatile().hash(state);
}
}
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);
}
}