Skip to content

Commit 53c30e7

Browse files
authored
Merge pull request #60 from mkroening/general-restrict
feat: introduce `RestrictAccess<To>` and generalize `restrict` to all access types
2 parents e334f2a + c64c9af commit 53c30e7

File tree

3 files changed

+90
-47
lines changed

3 files changed

+90
-47
lines changed

src/access.rs

+56-33
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,84 @@
11
//! Marker types for limiting access.
22
3-
/// Sealed trait that is implemented for the types in this module.
4-
pub trait Access: Copy + Default + private::Sealed {
5-
/// Reduced access level to safely share the corresponding value.
6-
type RestrictShared: Access;
3+
/// A trait for restricting one [`Access`] type to another [`Access`] type.
4+
///
5+
/// Restricting `Self` to `To` results in [`Self::Restricted`].
6+
///
7+
/// Restriction is a symmetric operation which is denoted by ∩, as it is the intersection of permissions.
8+
/// The following table holds:
9+
///
10+
/// | `Self` | `To` | `Self` ∩ `To` |
11+
/// | ------------- | ------------- | ------------- |
12+
/// | `T` | `T` | `T` |
13+
/// | [`ReadWrite`] | `T` | `T` |
14+
/// | [`NoAccess`] | `T` | [`NoAccess`] |
15+
/// | [`ReadOnly`] | [`WriteOnly`] | [`NoAccess`] |
16+
pub trait RestrictAccess<To>: Access {
17+
/// The resulting [`Access`] type of `Self` restricted to `To`.
18+
type Restricted: Access;
719
}
820

9-
/// Helper trait that is implemented by [`ReadWrite`] and [`ReadOnly`].
10-
pub trait Readable: Copy + Default + private::Sealed {
11-
/// Reduced access level to safely share the corresponding value.
12-
type RestrictShared: Readable + Access;
21+
impl<To: Access> RestrictAccess<To> for ReadWrite {
22+
type Restricted = To;
1323
}
1424

25+
impl<To> RestrictAccess<To> for NoAccess {
26+
type Restricted = Self;
27+
}
28+
29+
// Sadly, we cannot provide more generic implementations, since they would overlap.
30+
macro_rules! restrict_impl {
31+
($SelfT:ty, $To:ty, $Restricted:ty) => {
32+
impl RestrictAccess<$To> for $SelfT {
33+
type Restricted = $Restricted;
34+
}
35+
};
36+
}
37+
38+
restrict_impl!(ReadOnly, ReadWrite, ReadOnly);
39+
restrict_impl!(ReadOnly, ReadOnly, ReadOnly);
40+
restrict_impl!(ReadOnly, WriteOnly, NoAccess);
41+
restrict_impl!(ReadOnly, NoAccess, NoAccess);
42+
43+
restrict_impl!(WriteOnly, ReadWrite, WriteOnly);
44+
restrict_impl!(WriteOnly, ReadOnly, NoAccess);
45+
restrict_impl!(WriteOnly, WriteOnly, WriteOnly);
46+
restrict_impl!(WriteOnly, NoAccess, NoAccess);
47+
48+
/// Sealed trait that is implemented for the types in this module.
49+
pub trait Access: Copy + Default + private::Sealed {}
50+
51+
/// Helper trait that is implemented by [`ReadWrite`] and [`ReadOnly`].
52+
pub trait Readable: Access {}
53+
impl<A: RestrictAccess<ReadOnly, Restricted = ReadOnly>> Readable for A {}
54+
1555
/// Helper trait that is implemented by [`ReadWrite`] and [`WriteOnly`].
16-
pub trait Writable: Access + private::Sealed {}
56+
pub trait Writable: Access {}
57+
impl<A: RestrictAccess<WriteOnly, Restricted = WriteOnly>> Writable for A {}
1758

1859
/// Implemented for access types that permit copying of `VolatileRef`.
19-
pub trait Copyable: private::Sealed {}
20-
21-
impl<T> Access for T
22-
where
23-
T: Readable + Default + Copy,
24-
{
25-
type RestrictShared = <T as Readable>::RestrictShared;
26-
}
60+
pub trait Copyable: Access {}
61+
impl<A: RestrictAccess<ReadOnly, Restricted = Self>> Copyable for A {}
2762

2863
/// Zero-sized marker type for allowing both read and write access.
2964
#[derive(Debug, Default, Copy, Clone)]
3065
pub struct ReadWrite;
31-
impl Readable for ReadWrite {
32-
type RestrictShared = ReadOnly;
33-
}
34-
impl Writable for ReadWrite {}
66+
impl Access for ReadWrite {}
3567

3668
/// Zero-sized marker type for allowing only read access.
3769
#[derive(Debug, Default, Copy, Clone)]
3870
pub struct ReadOnly;
39-
impl Readable for ReadOnly {
40-
type RestrictShared = ReadOnly;
41-
}
42-
impl Copyable for ReadOnly {}
71+
impl Access for ReadOnly {}
4372

4473
/// Zero-sized marker type for allowing only write access.
4574
#[derive(Debug, Default, Copy, Clone)]
4675
pub struct WriteOnly;
47-
impl Access for WriteOnly {
48-
type RestrictShared = NoAccess;
49-
}
50-
impl Writable for WriteOnly {}
76+
impl Access for WriteOnly {}
5177

5278
/// Zero-sized marker type that grants no access.
5379
#[derive(Debug, Default, Copy, Clone)]
5480
pub struct NoAccess;
55-
impl Access for NoAccess {
56-
type RestrictShared = NoAccess;
57-
}
58-
impl Copyable for NoAccess {}
81+
impl Access for NoAccess {}
5982

6083
mod private {
6184
pub trait Sealed {}

src/volatile_ptr/operations.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use core::{
44
};
55

66
use crate::{
7-
access::{Access, ReadOnly, ReadWrite, Readable, Writable, WriteOnly},
7+
access::{Access, ReadOnly, ReadWrite, Readable, RestrictAccess, Writable, WriteOnly},
88
VolatilePtr,
99
};
1010

@@ -211,7 +211,7 @@ where
211211
}
212212

213213
/// Methods for restricting access.
214-
impl<'a, T> VolatilePtr<'a, T, ReadWrite>
214+
impl<'a, T, A> VolatilePtr<'a, T, A>
215215
where
216216
T: ?Sized,
217217
{
@@ -220,7 +220,7 @@ where
220220
/// ## Example
221221
///
222222
/// ```
223-
/// use volatile::access::ReadOnly;
223+
/// use volatile::access::{ReadOnly, WriteOnly};
224224
/// use volatile::VolatilePtr;
225225
///
226226
/// let mut value: i16 = -4;
@@ -229,14 +229,24 @@ where
229229
/// let read_only = volatile.restrict::<ReadOnly>();
230230
/// assert_eq!(read_only.read(), -4);
231231
/// // read_only.write(10); // compile-time error
232+
///
233+
/// let no_access = read_only.restrict::<WriteOnly>();
234+
/// // no_access.read(); // compile-time error
235+
/// // no_access.write(10); // compile-time error
232236
/// ```
233-
pub fn restrict<A>(self) -> VolatilePtr<'a, T, A>
237+
pub fn restrict<To>(self) -> VolatilePtr<'a, T, A::Restricted>
234238
where
235-
A: Access,
239+
A: RestrictAccess<To>,
236240
{
237241
unsafe { VolatilePtr::new_restricted(Default::default(), self.pointer) }
238242
}
243+
}
239244

245+
/// Methods for restricting access.
246+
impl<'a, T> VolatilePtr<'a, T, ReadWrite>
247+
where
248+
T: ?Sized,
249+
{
240250
/// Restricts access permissions to read-only.
241251
///
242252
/// ## Example

src/volatile_ref.rs

+19-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
access::{Access, Copyable, ReadOnly, ReadWrite, WriteOnly},
2+
access::{Access, Copyable, ReadOnly, ReadWrite, RestrictAccess, WriteOnly},
33
volatile_ptr::VolatilePtr,
44
};
55
use core::{cmp::Ordering, fmt, hash, marker::PhantomData, ptr::NonNull};
@@ -139,9 +139,9 @@ where
139139
/// This method creates a `VolatileRef` tied to the lifetime of the `&VolatileRef` it is created from.
140140
/// This is useful for providing a volatile reference without moving the original `VolatileRef`.
141141
/// In comparison with creating a `&VolatileRef<'a, T>`, this avoids the additional indirection and lifetime.
142-
pub fn borrow(&self) -> VolatileRef<'_, T, A::RestrictShared>
142+
pub fn borrow(&self) -> VolatileRef<'_, T, A::Restricted>
143143
where
144-
A: Access,
144+
A: RestrictAccess<ReadOnly>,
145145
{
146146
unsafe { VolatileRef::new_restricted(Default::default(), self.pointer) }
147147
}
@@ -161,9 +161,9 @@ where
161161
/// Borrows this `VolatileRef` as a read-only [`VolatilePtr`].
162162
///
163163
/// Use this method to do (partial) volatile reads of the referenced data.
164-
pub fn as_ptr(&self) -> VolatilePtr<'_, T, A::RestrictShared>
164+
pub fn as_ptr(&self) -> VolatilePtr<'_, T, A::Restricted>
165165
where
166-
A: Access,
166+
A: RestrictAccess<ReadOnly>,
167167
{
168168
unsafe { VolatilePtr::new_restricted(Default::default(), self.pointer) }
169169
}
@@ -194,7 +194,7 @@ where
194194
}
195195

196196
/// Methods for restricting access.
197-
impl<'a, T> VolatileRef<'a, T, ReadWrite>
197+
impl<'a, T, A> VolatileRef<'a, T, A>
198198
where
199199
T: ?Sized,
200200
{
@@ -203,7 +203,7 @@ where
203203
/// ## Example
204204
///
205205
/// ```
206-
/// use volatile::access::ReadOnly;
206+
/// use volatile::access::{ReadOnly, WriteOnly};
207207
/// use volatile::VolatileRef;
208208
///
209209
/// let mut value: i16 = -4;
@@ -212,14 +212,24 @@ where
212212
/// let read_only = volatile.restrict::<ReadOnly>();
213213
/// assert_eq!(read_only.as_ptr().read(), -4);
214214
/// // read_only.as_ptr().write(10); // compile-time error
215+
///
216+
/// let no_access = read_only.restrict::<WriteOnly>();
217+
/// // no_access.read(); // compile-time error
218+
/// // no_access.write(10); // compile-time error
215219
/// ```
216-
pub fn restrict<A>(self) -> VolatileRef<'a, T, A>
220+
pub fn restrict<To>(self) -> VolatileRef<'a, T, A::Restricted>
217221
where
218-
A: Access,
222+
A: RestrictAccess<To>,
219223
{
220224
unsafe { VolatileRef::new_restricted(Default::default(), self.pointer) }
221225
}
226+
}
222227

228+
/// Methods for restricting access.
229+
impl<'a, T> VolatileRef<'a, T, ReadWrite>
230+
where
231+
T: ?Sized,
232+
{
223233
/// Restricts access permissions to read-only.
224234
///
225235
/// ## Example

0 commit comments

Comments
 (0)