use crate::{
access::{Access, Copyable, ReadOnly, ReadWrite, RestrictAccess, WriteOnly},
volatile_ptr::VolatilePtr,
};
use core::{cmp::Ordering, fmt, hash, marker::PhantomData, ptr::NonNull};
#[must_use]
#[repr(transparent)]
pub struct VolatileRef<'a, T, A = ReadWrite>
where
T: ?Sized,
{
pointer: NonNull<T>,
reference: PhantomData<&'a T>,
access: PhantomData<A>,
}
impl<'a, T> VolatileRef<'a, T>
where
T: ?Sized,
{
pub unsafe fn new(pointer: NonNull<T>) -> Self {
unsafe { VolatileRef::new_restricted(ReadWrite, pointer) }
}
pub const unsafe fn new_read_only(pointer: NonNull<T>) -> VolatileRef<'a, T, ReadOnly> {
unsafe { Self::new_restricted(ReadOnly, pointer) }
}
pub const unsafe fn new_restricted<A>(access: A, pointer: NonNull<T>) -> VolatileRef<'a, T, A>
where
A: Access,
{
let _ = access;
unsafe { Self::new_generic(pointer) }
}
pub fn from_ref(reference: &'a T) -> VolatileRef<'a, T, ReadOnly>
where
T: 'a,
{
unsafe { VolatileRef::new_restricted(ReadOnly, reference.into()) }
}
pub fn from_mut_ref(reference: &'a mut T) -> Self
where
T: 'a,
{
unsafe { VolatileRef::new(reference.into()) }
}
const unsafe fn new_generic<A>(pointer: NonNull<T>) -> VolatileRef<'a, T, A> {
VolatileRef {
pointer,
reference: PhantomData,
access: PhantomData,
}
}
}
impl<'a, T, A> VolatileRef<'a, T, A>
where
T: ?Sized,
{
pub fn borrow(&self) -> VolatileRef<'_, T, A::Restricted>
where
A: RestrictAccess<ReadOnly>,
{
unsafe { VolatileRef::new_restricted(Default::default(), self.pointer) }
}
pub fn borrow_mut(&mut self) -> VolatileRef<'_, T, A>
where
A: Access,
{
unsafe { VolatileRef::new_restricted(Default::default(), self.pointer) }
}
pub fn as_ptr(&self) -> VolatilePtr<'_, T, A::Restricted>
where
A: RestrictAccess<ReadOnly>,
{
unsafe { VolatilePtr::new_restricted(Default::default(), self.pointer) }
}
pub fn as_mut_ptr(&mut self) -> VolatilePtr<'_, T, A>
where
A: Access,
{
unsafe { VolatilePtr::new_restricted(Default::default(), self.pointer) }
}
pub fn into_ptr(self) -> VolatilePtr<'a, T, A>
where
A: Access,
{
unsafe { VolatilePtr::new_restricted(Default::default(), self.pointer) }
}
}
impl<'a, T, A> VolatileRef<'a, T, A>
where
T: ?Sized,
{
pub fn restrict<To>(self) -> VolatileRef<'a, T, A::Restricted>
where
A: RestrictAccess<To>,
{
unsafe { VolatileRef::new_restricted(Default::default(), self.pointer) }
}
}
impl<'a, T> VolatileRef<'a, T, ReadWrite>
where
T: ?Sized,
{
pub fn read_only(self) -> VolatileRef<'a, T, ReadOnly> {
self.restrict()
}
pub fn write_only(self) -> VolatileRef<'a, T, WriteOnly> {
self.restrict()
}
}
impl<'a, T, A> Clone for VolatileRef<'a, T, A>
where
T: ?Sized,
A: Access + Copyable,
{
fn clone(&self) -> Self {
*self
}
}
impl<'a, T, A> Copy for VolatileRef<'a, T, A>
where
T: ?Sized,
A: Access + Copyable,
{
}
unsafe impl<T, A> Send for VolatileRef<'_, T, A> where T: Sync + ?Sized {}
unsafe impl<T, A> Sync for VolatileRef<'_, T, A> where T: Sync + ?Sized {}
impl<T, A> fmt::Debug for VolatileRef<'_, T, A>
where
T: ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.pointer.as_ptr(), f)
}
}
impl<T, A> fmt::Pointer for VolatileRef<'_, T, A>
where
T: ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.pointer.as_ptr(), f)
}
}
impl<T, A> PartialEq for VolatileRef<'_, T, A>
where
T: ?Sized,
{
fn eq(&self, other: &Self) -> bool {
core::ptr::eq(self.pointer.as_ptr(), other.pointer.as_ptr())
}
}
impl<T, A> Eq for VolatileRef<'_, T, A> where T: ?Sized {}
impl<T, A> PartialOrd for VolatileRef<'_, T, A>
where
T: ?Sized,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T, A> Ord for VolatileRef<'_, T, A>
where
T: ?Sized,
{
fn cmp(&self, other: &Self) -> Ordering {
#[allow(ambiguous_wide_pointer_comparisons)]
Ord::cmp(&self.pointer.as_ptr(), &other.pointer.as_ptr())
}
}
impl<T, A> hash::Hash for VolatileRef<'_, T, A>
where
T: ?Sized,
{
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.pointer.as_ptr().hash(state);
}
}