11//! Type-safe volatile pointer implementation.
22//!
3- //! [`VolatilePtr`] is a transparent wrapper around a raw pointer that uses
3+ //! [`VolatilePtr`] is a transparent wrapper around a raw pointer that uses
44//! type-state patterns to enforce access rights at compile time.
55
66use crate :: access:: { RO , RW , VolatilePtrAccess , WO } ;
@@ -35,18 +35,45 @@ impl<T> VolatilePtr<RW, T> {
3535 }
3636
3737 /// Performs a volatile read.
38+ ///
39+ /// # Safety
40+ ///
41+ /// This function is unsafe because it performs a raw pointer dereference.
42+ /// The caller must ensure that:
43+ /// - The pointer is aligned for type `T`.
44+ /// - The pointer is valid for reads and points to initialized memory (or a valid MMIO register).
45+ /// - No other thread is performing a non-volatile write to this memory location simultaneously.
3846 #[ inline]
3947 pub unsafe fn read ( & self ) -> T {
4048 unsafe { ptr:: read_volatile ( self . address ) }
4149 }
4250
4351 /// Performs a volatile write.
52+ ///
53+ /// # Safety
54+ ///
55+ /// This function is unsafe because it performs a raw pointer dereference.
56+ /// The caller must ensure that:
57+ /// - The pointer is aligned for type `T`.
58+ /// - The pointer is valid for writes.
59+ /// - The memory address is mapped and accessible by the process/core.
4460 #[ inline]
4561 pub unsafe fn write ( & self , value : T ) {
4662 unsafe { ptr:: write_volatile ( self . address , value) }
4763 }
4864
4965 /// Modifies the value using a closure (Read-Modify-Write).
66+ ///
67+ /// # Safety
68+ ///
69+ /// This function is unsafe because it performs raw pointer dereferences.
70+ /// The caller must ensure the same safety requirements as for [`Self::read`] and [`Self::write`].
71+ ///
72+ /// # Important: Non-atomicity
73+ ///
74+ /// This operation is **not atomic**. It performs a separate read and a separate write.
75+ /// In a multi-threaded environment or in the presence of interrupts that modify the same
76+ /// register, a race condition may occur between the read and the write.
5077 #[ inline]
5178 pub unsafe fn set ( & self , set_fn : impl FnOnce ( T ) -> T ) {
5279 unsafe {
@@ -63,20 +90,36 @@ impl<T> VolatilePtr<RW, T> {
6390 }
6491
6592 /// Calculates an offset from the pointer using typed arithmetic.
66- ///
93+ ///
6794 /// The offset is multiplied by `size_of::<T>()`.
95+ ///
96+ /// # Safety
97+ ///
98+ /// The caller must ensure that the resulting pointer is within the bounds
99+ /// of the same allocated object or a valid memory-mapped region.
68100 #[ inline]
69101 pub const unsafe fn add ( & self , count : usize ) -> Self {
70102 Self :: from_ptr ( unsafe { self . get_address ( ) . add ( count) } )
71103 }
72104
73105 /// Calculates a byte-based offset from the pointer.
106+ ///
107+ /// # Safety
108+ ///
109+ /// The caller must ensure that the resulting pointer is within the bounds
110+ /// of the same allocated object or a valid memory-mapped region.
74111 #[ inline]
75112 pub const unsafe fn byte_add ( & self , count : usize ) -> Self {
76113 Self :: from_ptr ( unsafe { self . get_address ( ) . byte_add ( count) } )
77114 }
78115
79116 /// Calculates a byte-based offset using wrapping arithmetic.
117+ ///
118+ /// # Safety
119+ ///
120+ /// While this method uses wrapping arithmetic, the caller is responsible
121+ /// for ensuring that the resulting address points to a valid memory location
122+ /// before performing any read or write operations.
80123 #[ inline]
81124 pub const unsafe fn raw_byte_add ( & self , count : usize ) -> Self {
82125 let ptr = self . get_address ( ) as * mut u8 ;
@@ -85,6 +128,12 @@ impl<T> VolatilePtr<RW, T> {
85128 }
86129
87130 /// Spins until the register matches the expected value.
131+ ///
132+ /// # Safety
133+ ///
134+ /// The caller must ensure that the address is valid for volatile reads.
135+ /// This is a busy-wait loop; it is the caller's responsibility to ensure
136+ /// the condition will eventually be met to avoid a permanent hang.
88137 #[ inline]
89138 pub unsafe fn wait_until ( & self , value : T , mut spin_hint : impl FnMut ( ) )
90139 where
@@ -106,12 +155,26 @@ where
106155 // RW
107156
108157 /// Sets bits using a bitwise mask (`v | mask`).
158+ ///
159+ /// # Safety
160+ ///
161+ /// This function is unsafe because it performs raw pointer dereferences.
162+ /// The caller must ensure the same safety requirements as for [`Self::read`] and [`Self::write`].
163+ ///
164+ /// Note that this is a non-atomic Read-Modify-Write operation.
109165 #[ inline]
110166 pub unsafe fn set_bits ( & self , mask : T ) {
111167 unsafe { self . set ( |v| v | mask) } ;
112168 }
113169
114170 /// Clears bits using a bitwise mask (`v & !mask`).
171+ ///
172+ /// # Safety
173+ ///
174+ /// This function is unsafe because it performs raw pointer dereferences.
175+ /// The caller must ensure the same safety requirements as for [`Self::read`] and [`Self::write`].
176+ ///
177+ /// Note that this is a non-atomic Read-Modify-Write operation.
115178 #[ inline]
116179 pub unsafe fn clear_bits ( & self , mask : T ) {
117180 unsafe { self . set ( |v| v & !mask) } ;
@@ -127,6 +190,14 @@ impl<T> VolatilePtr<RO, T> {
127190 }
128191
129192 /// Performs a volatile read.
193+ ///
194+ /// # Safety
195+ ///
196+ /// This function is unsafe because it performs a raw pointer dereference.
197+ /// The caller must ensure that:
198+ /// - The pointer is aligned for type `T`.
199+ /// - The pointer is valid for reads and points to initialized memory (or a valid MMIO register).
200+ /// - No other thread is performing a non-volatile write to this memory location simultaneously.
130201 #[ inline]
131202 pub unsafe fn read ( & self ) -> T {
132203 unsafe { ptr:: read_volatile ( self . address ) }
@@ -139,20 +210,36 @@ impl<T> VolatilePtr<RO, T> {
139210 }
140211
141212 /// Calculates an offset from the pointer using typed arithmetic.
142- ///
213+ ///
143214 /// The offset is multiplied by `size_of::<T>()`.
215+ ///
216+ /// # Safety
217+ ///
218+ /// The caller must ensure that the resulting pointer is within the bounds
219+ /// of the same allocated object or a valid memory-mapped region.
144220 #[ inline]
145221 pub const unsafe fn add ( & self , count : usize ) -> Self {
146222 Self :: from_ptr ( unsafe { self . get_address ( ) . add ( count) } )
147223 }
148224
149225 /// Calculates a byte-based offset from the pointer.
226+ ///
227+ /// # Safety
228+ ///
229+ /// The caller must ensure that the resulting pointer is within the bounds
230+ /// of the same allocated object or a valid memory-mapped region.
150231 #[ inline]
151232 pub const unsafe fn byte_add ( & self , count : usize ) -> Self {
152233 Self :: from_ptr ( unsafe { self . get_address ( ) . byte_add ( count) } )
153234 }
154235
155236 /// Calculates a byte-based offset using wrapping arithmetic.
237+ ///
238+ /// # Safety
239+ ///
240+ /// While this method uses wrapping arithmetic, the caller is responsible
241+ /// for ensuring that the resulting address points to a valid memory location
242+ /// before performing any read or write operations.
156243 #[ inline]
157244 pub const unsafe fn raw_byte_add ( & self , count : usize ) -> Self {
158245 let ptr = self . get_address ( ) as * mut u8 ;
@@ -161,6 +248,12 @@ impl<T> VolatilePtr<RO, T> {
161248 }
162249
163250 /// Spins until the register matches the expected value.
251+ ///
252+ /// # Safety
253+ ///
254+ /// The caller must ensure that the address is valid for volatile reads.
255+ /// This is a busy-wait loop; it is the caller's responsibility to ensure
256+ /// the condition will eventually be met to avoid a permanent hang.
164257 #[ inline]
165258 pub unsafe fn wait_until ( & self , value : T , mut spin_hint : impl FnMut ( ) )
166259 where
@@ -181,6 +274,14 @@ impl<T> VolatilePtr<WO, T> {
181274 }
182275
183276 /// Performs a volatile write.
277+ ///
278+ /// # Safety
279+ ///
280+ /// This function is unsafe because it performs a raw pointer dereference.
281+ /// The caller must ensure that:
282+ /// - The pointer is aligned for type `T`.
283+ /// - The pointer is valid for writes.
284+ /// - The memory address is mapped and accessible by the process/core.
184285 #[ inline]
185286 pub unsafe fn write ( & self , value : T ) {
186287 unsafe { ptr:: write_volatile ( self . address , value) }
@@ -193,20 +294,36 @@ impl<T> VolatilePtr<WO, T> {
193294 }
194295
195296 /// Calculates an offset from the pointer using typed arithmetic.
196- ///
297+ ///
197298 /// The offset is multiplied by `size_of::<T>()`.
299+ ///
300+ /// # Safety
301+ ///
302+ /// The caller must ensure that the resulting pointer is within the bounds
303+ /// of the same allocated object or a valid memory-mapped region.
198304 #[ inline]
199305 pub const unsafe fn add ( & self , count : usize ) -> Self {
200306 Self :: from_ptr ( unsafe { self . get_address ( ) . add ( count) } )
201307 }
202308
203309 /// Calculates a byte-based offset from the pointer.
310+ ///
311+ /// # Safety
312+ ///
313+ /// The caller must ensure that the resulting pointer is within the bounds
314+ /// of the same allocated object or a valid memory-mapped region.
204315 #[ inline]
205316 pub const unsafe fn byte_add ( & self , count : usize ) -> Self {
206317 Self :: from_ptr ( unsafe { self . get_address ( ) . byte_add ( count) } )
207318 }
208319
209320 /// Calculates a byte-based offset using wrapping arithmetic.
321+ ///
322+ /// # Safety
323+ ///
324+ /// While this method uses wrapping arithmetic, the caller is responsible
325+ /// for ensuring that the resulting address points to a valid memory location
326+ /// before performing any read or write operations.
210327 #[ inline]
211328 pub const unsafe fn raw_byte_add ( & self , count : usize ) -> Self {
212329 let ptr = self . get_address ( ) as * mut u8 ;
@@ -223,7 +340,7 @@ where
223340 #[ inline]
224341 pub const fn from_ptr ( address : A :: TPtr ) -> Self {
225342 Self {
226- address : address ,
343+ address,
227344 _access_marker : PhantomData ,
228345 _type_marker : PhantomData ,
229346 }
0 commit comments