volatile_mem/
volatile.rs

1use core::{
2    any::type_name,
3    borrow::{Borrow, BorrowMut},
4    fmt,
5    marker::PhantomData,
6    ops::{Deref, DerefMut},
7    slice,
8};
9
10use crate::{VolatileData, VolatileRead, VolatileWrite};
11
12#[derive(Debug)]
13pub struct ReadWrite;
14#[derive(Debug)]
15pub struct ReadOnly;
16#[derive(Debug)]
17pub struct WriteOnly;
18
19pub trait Read {}
20impl Read for ReadWrite {}
21impl Read for ReadOnly {}
22
23pub trait Write {}
24impl Write for ReadWrite {}
25impl Write for WriteOnly {}
26
27/// Volatile data or memory.
28///
29/// See [crate-level documentation](crate) for details.
30#[repr(C)]
31pub union Volatile<T: Copy, Permission = ReadWrite> {
32    _data: T,
33    _perm: PhantomData<Permission>,
34}
35
36/// Volatile read-only data or memory.
37///
38/// See [crate-level documentation](crate) for details.
39///
40/// See [`Volatile<T>`] for methods and [methods](Volatile<T>#implementations)
41/// and [trait implementations](Volatile<T>#trait-implementations).
42pub type VolatileReadOnly<T> = Volatile<T, ReadOnly>;
43
44/// Volatile write-only data or memory.
45///
46/// See [crate-level documentation](crate) for details.
47///
48/// See [`Volatile<T>`] for methods and [methods](Volatile<T>#implementations)
49/// and [trait implementations](Volatile<T>#trait-implementations).
50pub type VolatileWriteOnly<T> = Volatile<T, WriteOnly>;
51
52impl<T: Copy, P> Volatile<T, P> {
53    /// Converts a pointer to `T` into a reference to `Volatile<T>`, which can
54    /// be [read-only](VolatileReadOnly), [write-only](VolatileWriteOnly), or
55    /// both readable and writable (the default).
56    ///
57    /// # Safety
58    /// Behavior is undefined if any of the following conditions are violated:
59    ///
60    /// - `mem` must be [valid](core::ptr#safety) for reads and/or writes.
61    ///
62    /// - `mem` must be properly aligned.
63    ///
64    /// - `mem` must point to a properly initialized value of type `T` (unless
65    /// the resulting `Volatile<T>` is [write-only](VolatileWriteOnly)).
66    ///
67    /// Note that even if `T` has size zero, the pointer must be non-NULL and
68    /// properly aligned.
69    ///
70    /// Just like in C, whether an operation is volatile has no bearing
71    /// whatsoever on questions involving concurrent access from multiple
72    /// threads. Volatile accesses behave exactly like non-atomic accesses in
73    /// that regard. In particular, a race between a write operation any other
74    /// operation (reading or writing) to the same location is undefined
75    /// behavior.
76    pub unsafe fn from_ptr<'a>(mem: *const T) -> &'a Self {
77        // SAFETY: The caller must ensure the pointer is safe to use. It is
78        // safe to cast to `*const Self` because `Self` is transparent.
79        unsafe { &*(mem as *const Self) }
80    }
81
82    /// Converts a mutable pointer to `T` into a mutable reference to
83    /// `Volatile<T>`, which can be [read-only](VolatileReadOnly),
84    /// [write-only](VolatileWriteOnly), or both readable and writable (the
85    /// default).
86    ///
87    /// # Safety
88    /// Behavior is undefined if any of the following conditions are violated:
89    ///
90    /// - `mem` must be [valid](core::ptr#safety) for reads and/or writes.
91    ///
92    /// - `mem` must be properly aligned.
93    ///
94    /// - `mem` must point to a properly initialized value of type `T` (unless
95    /// the resulting `Volatile<T>` is [write-only](VolatileWriteOnly)).
96    ///
97    /// Note that even if `T` has size zero, the pointer must be non-NULL and
98    /// properly aligned.
99    pub unsafe fn from_mut_ptr<'a>(mem: *mut T) -> &'a mut Self {
100        // SAFETY: The caller must ensure the pointer is safe to use. It is
101        // safe to cast to `*mut Self` because `Self` is transparent.
102        unsafe { &mut *(mem as *mut Self) }
103    }
104
105    /// Converts a shared reference to `T` into a shared reference to
106    /// `Volatile<T>`, which can be [read-only](VolatileReadOnly),
107    /// [write-only](VolatileWriteOnly), or both readable and writable (the
108    /// default).
109    pub fn from_ref<'a>(mem: &T) -> &'a Self {
110        // SAFETY: `mem` is a reference to a `Copy` type. It is safe to cast to
111        // `*const Self` because `Self` is transparent.
112        unsafe { &*(mem as *const T as *const Volatile<T, P>) }
113    }
114
115    /// Converts a mutable reference to `T` into a mutable reference to
116    /// `Volatile<T>`, which can be [read-only](VolatileReadOnly),
117    /// [write-only](VolatileWriteOnly), or both readable and writable (the
118    /// default).
119    pub fn from_mut<'a>(mem: &mut T) -> &'a mut Self {
120        // SAFETY: `mem` is a mutable reference to a `Copy` type. It is safe to
121        // cast to `*mut Self` because `Self` is transparent.
122        unsafe { &mut *(mem as *mut T as *mut Volatile<T, P>) }
123    }
124}
125
126impl<'a, T: Copy, P> From<&'a T> for &'a Volatile<T, P> {
127    fn from(mem: &'a T) -> &'a Volatile<T, P> {
128        Volatile::from_ref(mem)
129    }
130}
131
132impl<'a, T: Copy, P> From<&'a mut T> for &'a mut Volatile<T, P> {
133    fn from(mem: &'a mut T) -> &'a mut Volatile<T, P> {
134        Volatile::from_mut(mem)
135    }
136}
137
138impl<T: Copy, P> VolatileData<T> for Volatile<T, P> {}
139
140impl<T: Copy, P: Read> VolatileRead<T> for Volatile<T, P> {
141    /// Performs a volatile read of the value in `self` without moving it. This
142    /// leaves the memory in `self` unchanged.
143    fn read(&self) -> T {
144        // SAFETY: `self` is a reference. It is safe to cast to `*const T`
145        // because `Self` is transparent. `T` is safe to read since it is `Copy`
146        // and guaranteed to be initialized.
147        unsafe { (self as *const _ as *const T).read_volatile() }
148    }
149}
150
151impl<T: Copy, P: Write> VolatileWrite<T> for Volatile<T, P> {
152    /// Performs a volatile write of `self` with the given value without reading
153    /// the old value.
154    fn write(&mut self, val: T) {
155        // SAFETY: `self` is a mutable reference. It is safe to cast to `*mut T`
156        // because `Self` is transparent. `T` is safe to write since it is
157        // `Copy`.
158        unsafe { (self as *mut _ as *mut T).write_volatile(val) }
159    }
160}
161
162impl<T: Copy, P, const N: usize> Deref for Volatile<[T; N], P> {
163    type Target = [Volatile<T, P>];
164
165    fn deref(&self) -> &Self::Target {
166        let ptr = self as *const _ as *const Volatile<T, P>;
167        // SAFETY: `ptr` is valid for N elements of `Volatile<T>`, because it
168        // comes from a reference to `Volatile<[T; N]>` and `Volatile` is
169        // transparent.
170        unsafe { slice::from_raw_parts(ptr, N) }
171    }
172}
173
174impl<T: Copy, P, const N: usize> DerefMut for Volatile<[T; N], P> {
175    fn deref_mut(&mut self) -> &mut Self::Target {
176        let ptr = self as *mut _ as *mut Volatile<T, P>;
177        // SAFETY: `ptr` is valid for N elements of `Volatile<T>`, because it
178        // comes from a reference to `Volatile<[T; N]>` and `Volatile` is
179        // transparent.
180        unsafe { slice::from_raw_parts_mut(ptr, N) }
181    }
182}
183
184impl<T: Copy, P, const N: usize> Borrow<[Volatile<T, P>]> for Volatile<[T; N], P> {
185    fn borrow(&self) -> &[Volatile<T, P>] {
186        self
187    }
188}
189
190impl<T: Copy, P, const N: usize> BorrowMut<[Volatile<T, P>]> for Volatile<[T; N], P> {
191    fn borrow_mut(&mut self) -> &mut [Volatile<T, P>] {
192        self
193    }
194}
195
196impl<T: Copy, P, const N: usize> AsRef<[Volatile<T, P>]> for Volatile<[T; N], P> {
197    fn as_ref(&self) -> &[Volatile<T, P>] {
198        self
199    }
200}
201
202impl<T: Copy, P, const N: usize> AsMut<[Volatile<T, P>]> for Volatile<[T; N], P> {
203    fn as_mut(&mut self) -> &mut [Volatile<T, P>] {
204        self
205    }
206}
207
208impl<T: Copy, P> fmt::Debug for Volatile<T, P> {
209    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210        f.pad(type_name::<Self>())
211    }
212}