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}