diff --git a/src/access.rs b/src/access.rs index 6d529bd..19b29bf 100644 --- a/src/access.rs +++ b/src/access.rs @@ -1,61 +1,84 @@ //! Marker types for limiting access. -/// Sealed trait that is implemented for the types in this module. -pub trait Access: Copy + Default + private::Sealed { - /// Reduced access level to safely share the corresponding value. - type RestrictShared: Access; +/// A trait for restricting one [`Access`] type to another [`Access`] type. +/// +/// Restricting `Self` to `To` results in [`Self::Restricted`]. +/// +/// Restriction is a symmetric operation which is denoted by ∩, as it is the intersection of permissions. +/// The following table holds: +/// +/// | `Self` | `To` | `Self` ∩ `To` | +/// | ------------- | ------------- | ------------- | +/// | `T` | `T` | `T` | +/// | [`ReadWrite`] | `T` | `T` | +/// | [`NoAccess`] | `T` | [`NoAccess`] | +/// | [`ReadOnly`] | [`WriteOnly`] | [`NoAccess`] | +pub trait RestrictAccess: Access { + /// The resulting [`Access`] type of `Self` restricted to `To`. + type Restricted: Access; } -/// Helper trait that is implemented by [`ReadWrite`] and [`ReadOnly`]. -pub trait Readable: Copy + Default + private::Sealed { - /// Reduced access level to safely share the corresponding value. - type RestrictShared: Readable + Access; +impl RestrictAccess for ReadWrite { + type Restricted = To; } +impl RestrictAccess for NoAccess { + type Restricted = Self; +} + +// Sadly, we cannot provide more generic implementations, since they would overlap. +macro_rules! restrict_impl { + ($SelfT:ty, $To:ty, $Restricted:ty) => { + impl RestrictAccess<$To> for $SelfT { + type Restricted = $Restricted; + } + }; +} + +restrict_impl!(ReadOnly, ReadWrite, ReadOnly); +restrict_impl!(ReadOnly, ReadOnly, ReadOnly); +restrict_impl!(ReadOnly, WriteOnly, NoAccess); +restrict_impl!(ReadOnly, NoAccess, NoAccess); + +restrict_impl!(WriteOnly, ReadWrite, WriteOnly); +restrict_impl!(WriteOnly, ReadOnly, NoAccess); +restrict_impl!(WriteOnly, WriteOnly, WriteOnly); +restrict_impl!(WriteOnly, NoAccess, NoAccess); + +/// Sealed trait that is implemented for the types in this module. +pub trait Access: Copy + Default + private::Sealed {} + +/// Helper trait that is implemented by [`ReadWrite`] and [`ReadOnly`]. +pub trait Readable: Access {} +impl> Readable for A {} + /// Helper trait that is implemented by [`ReadWrite`] and [`WriteOnly`]. -pub trait Writable: Access + private::Sealed {} +pub trait Writable: Access {} +impl> Writable for A {} /// Implemented for access types that permit copying of `VolatileRef`. -pub trait Copyable: private::Sealed {} - -impl Access for T -where - T: Readable + Default + Copy, -{ - type RestrictShared = ::RestrictShared; -} +pub trait Copyable: Access {} +impl> Copyable for A {} /// Zero-sized marker type for allowing both read and write access. #[derive(Debug, Default, Copy, Clone)] pub struct ReadWrite; -impl Readable for ReadWrite { - type RestrictShared = ReadOnly; -} -impl Writable for ReadWrite {} +impl Access for ReadWrite {} /// Zero-sized marker type for allowing only read access. #[derive(Debug, Default, Copy, Clone)] pub struct ReadOnly; -impl Readable for ReadOnly { - type RestrictShared = ReadOnly; -} -impl Copyable for ReadOnly {} +impl Access for ReadOnly {} /// Zero-sized marker type for allowing only write access. #[derive(Debug, Default, Copy, Clone)] pub struct WriteOnly; -impl Access for WriteOnly { - type RestrictShared = NoAccess; -} -impl Writable for WriteOnly {} +impl Access for WriteOnly {} /// Zero-sized marker type that grants no access. #[derive(Debug, Default, Copy, Clone)] pub struct NoAccess; -impl Access for NoAccess { - type RestrictShared = NoAccess; -} -impl Copyable for NoAccess {} +impl Access for NoAccess {} mod private { pub trait Sealed {} diff --git a/src/volatile_ptr/operations.rs b/src/volatile_ptr/operations.rs index 54c172d..05fbb5b 100644 --- a/src/volatile_ptr/operations.rs +++ b/src/volatile_ptr/operations.rs @@ -4,7 +4,7 @@ use core::{ }; use crate::{ - access::{Access, ReadOnly, ReadWrite, Readable, Writable, WriteOnly}, + access::{Access, ReadOnly, ReadWrite, Readable, RestrictAccess, Writable, WriteOnly}, VolatilePtr, }; @@ -211,7 +211,7 @@ where } /// Methods for restricting access. -impl<'a, T> VolatilePtr<'a, T, ReadWrite> +impl<'a, T, A> VolatilePtr<'a, T, A> where T: ?Sized, { @@ -220,7 +220,7 @@ where /// ## Example /// /// ``` - /// use volatile::access::ReadOnly; + /// use volatile::access::{ReadOnly, WriteOnly}; /// use volatile::VolatilePtr; /// /// let mut value: i16 = -4; @@ -229,14 +229,24 @@ where /// let read_only = volatile.restrict::(); /// assert_eq!(read_only.read(), -4); /// // read_only.write(10); // compile-time error + /// + /// let no_access = read_only.restrict::(); + /// // no_access.read(); // compile-time error + /// // no_access.write(10); // compile-time error /// ``` - pub fn restrict(self) -> VolatilePtr<'a, T, A> + pub fn restrict(self) -> VolatilePtr<'a, T, A::Restricted> where - A: Access, + A: RestrictAccess, { unsafe { VolatilePtr::new_restricted(Default::default(), self.pointer) } } +} +/// Methods for restricting access. +impl<'a, T> VolatilePtr<'a, T, ReadWrite> +where + T: ?Sized, +{ /// Restricts access permissions to read-only. /// /// ## Example diff --git a/src/volatile_ref.rs b/src/volatile_ref.rs index 3b98ac5..5de3287 100644 --- a/src/volatile_ref.rs +++ b/src/volatile_ref.rs @@ -1,5 +1,5 @@ use crate::{ - access::{Access, Copyable, ReadOnly, ReadWrite, WriteOnly}, + access::{Access, Copyable, ReadOnly, ReadWrite, RestrictAccess, WriteOnly}, volatile_ptr::VolatilePtr, }; use core::{cmp::Ordering, fmt, hash, marker::PhantomData, ptr::NonNull}; @@ -139,9 +139,9 @@ where /// This method creates a `VolatileRef` tied to the lifetime of the `&VolatileRef` it is created from. /// This is useful for providing a volatile reference without moving the original `VolatileRef`. /// In comparison with creating a `&VolatileRef<'a, T>`, this avoids the additional indirection and lifetime. - pub fn borrow(&self) -> VolatileRef<'_, T, A::RestrictShared> + pub fn borrow(&self) -> VolatileRef<'_, T, A::Restricted> where - A: Access, + A: RestrictAccess, { unsafe { VolatileRef::new_restricted(Default::default(), self.pointer) } } @@ -161,9 +161,9 @@ where /// Borrows this `VolatileRef` as a read-only [`VolatilePtr`]. /// /// Use this method to do (partial) volatile reads of the referenced data. - pub fn as_ptr(&self) -> VolatilePtr<'_, T, A::RestrictShared> + pub fn as_ptr(&self) -> VolatilePtr<'_, T, A::Restricted> where - A: Access, + A: RestrictAccess, { unsafe { VolatilePtr::new_restricted(Default::default(), self.pointer) } } @@ -194,7 +194,7 @@ where } /// Methods for restricting access. -impl<'a, T> VolatileRef<'a, T, ReadWrite> +impl<'a, T, A> VolatileRef<'a, T, A> where T: ?Sized, { @@ -203,7 +203,7 @@ where /// ## Example /// /// ``` - /// use volatile::access::ReadOnly; + /// use volatile::access::{ReadOnly, WriteOnly}; /// use volatile::VolatileRef; /// /// let mut value: i16 = -4; @@ -212,14 +212,24 @@ where /// let read_only = volatile.restrict::(); /// assert_eq!(read_only.as_ptr().read(), -4); /// // read_only.as_ptr().write(10); // compile-time error + /// + /// let no_access = read_only.restrict::(); + /// // no_access.read(); // compile-time error + /// // no_access.write(10); // compile-time error /// ``` - pub fn restrict(self) -> VolatileRef<'a, T, A> + pub fn restrict(self) -> VolatileRef<'a, T, A::Restricted> where - A: Access, + A: RestrictAccess, { unsafe { VolatileRef::new_restricted(Default::default(), self.pointer) } } +} +/// Methods for restricting access. +impl<'a, T> VolatileRef<'a, T, ReadWrite> +where + T: ?Sized, +{ /// Restricts access permissions to read-only. /// /// ## Example