Skip to content

Commit b2a92ef

Browse files
committed
clippy: fix everything that clippy requires, add safety comments, fix some isolated moments in the code
1 parent 1ccce77 commit b2a92ef

5 files changed

Lines changed: 142 additions & 28 deletions

File tree

src/access.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
//! Access control markers for volatile pointers.
22
//!
3-
//! This module defines markers ([`RO`], [`RW`], [`WO`]) used to specify
4-
//! the capabilities of a [`VolatilePtr`]. These markers are zero-sized
3+
//! This module defines markers ([`RO`], [`RW`], [`WO`]) used to specify
4+
//! the capabilities of a [`VolatilePtr`]. These markers are zero-sized
55
//! and exist only to enforce access rules at compile time.
66
7-
use core::fmt::Debug;
87
use cluFullTransmute::transmute_unchecked;
8+
use core::fmt::Debug;
99

1010
/// A trait that defines how a specific access marker relates to raw pointers.
1111
pub trait VolatilePtrAccess<T>: Debug + Clone + Copy + PartialEq + PartialOrd + Eq + Ord {
@@ -19,8 +19,8 @@ pub trait VolatilePtrAccess<T>: Debug + Clone + Copy + PartialEq + PartialOrd +
1919
}
2020

2121
/// **Read-Only** access marker.
22-
///
23-
/// Pointers with this marker only allow `.read()` operations.
22+
///
23+
/// Pointers with this marker only allow `.read()` operations.
2424
/// Maps to `*const T`.
2525
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
2626
pub enum RO {}
@@ -40,7 +40,7 @@ impl<T> VolatilePtrAccess<T> for RO {
4040
}
4141

4242
/// **Read-Write** access marker.
43-
///
43+
///
4444
/// Pointers with this marker allow both `.read()` and `.write()` operations.
4545
/// Maps to `*mut T`.
4646
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -61,7 +61,7 @@ impl<T> VolatilePtrAccess<T> for RW {
6161
}
6262

6363
/// **Write-Only** access marker.
64-
///
64+
///
6565
/// Pointers with this marker only allow `.write()` operations.
6666
/// Maps to `*mut T`.
6767
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -82,9 +82,9 @@ impl<T> VolatilePtrAccess<T> for WO {
8282
}
8383

8484
/// Forcefully converts a raw pointer type to its address representation.
85-
///
85+
///
8686
/// # Safety
87-
/// This is used internally to perform address arithmetic. It relies on the fact
87+
/// This is used internally to perform address arithmetic. It relies on the fact
8888
/// that `*const T` and `*mut T` have the same layout as `usize`.
8989
pub(crate) const unsafe fn into_usize_unchecked<A: VolatilePtrAccess<T>, T>(v: A::TPtr) -> usize {
9090
unsafe { transmute_unchecked(v) }

src/lib.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ pub mod ptr;
2222

2323
/// A helper macro to resolve volatile pointer types and access rights.
2424
///
25-
/// This macro maps shorthand syntax (like `rw`, `ro`, `wo`) and data types
26-
/// to the underlying [`VolatilePtr`] implementation. It is the core engine
25+
/// This macro maps shorthand syntax (like `rw`, `ro`, `wo`) and data types
26+
/// to the underlying [`VolatilePtr`] implementation. It is the core engine
2727
/// behind the type generation in `volatile_table!`.
2828
///
2929
/// # Syntax Patterns:
@@ -80,7 +80,7 @@ macro_rules! volatile_type {
8080

8181
/// A universal constructor macro for creating volatile pointers.
8282
///
83-
/// This macro provides a flexible DSL for instantiating [`VolatilePtr`] from raw pointers
83+
/// This macro provides a flexible DSL for instantiating [`VolatilePtr`] from raw pointers
8484
/// or memory addresses (as `usize`). It handles access rights and type casting automatically.
8585
///
8686
/// # Syntax Variations:
@@ -94,7 +94,7 @@ macro_rules! volatile_type {
9494
///
9595
/// ```rust
9696
/// use volatile_table::volatile;
97-
///
97+
///
9898
/// static mut SOME_VAR: usize = 0;
9999
///
100100
/// // 1. Default (Read-Write, usize, from raw pointer)
@@ -185,7 +185,7 @@ macro_rules! volatile {
185185
/// /// System clock control
186186
/// pub rw <u32> CLK_CTRL = 0x4000_0000;
187187
/// /// Status register (read-only)
188-
/// ro <u32> STATUS = 0x4000_0004;
188+
/// ro <u32> STATUS = 0x4000_0004;
189189
/// }
190190
/// ```
191191
///
@@ -204,7 +204,7 @@ macro_rules! volatile {
204204
/// # How it works
205205
/// - For entries with `<type>`, the macro assumes the initialization value is a memory address (`usize`).
206206
/// - For entries without `<type>`, it treats the value as a pointer expression unless flagged.
207-
/// - The `map` block expands into a series of constant definitions where each child register
207+
/// - The `map` block expands into a series of constant definitions where each child register
208208
/// is calculated as `BASE_ADDR + OFFSET`.
209209
#[macro_export]
210210
macro_rules! volatile_table {
@@ -311,10 +311,10 @@ macro_rules! volatile_table {
311311
[ ] => [];
312312
}
313313

314-
/// **Internal use only.**
314+
/// **Internal use only.**
315315
///
316316
/// This macro handles the expansion of the `map` block within [`volatile_table!`].
317-
/// It recursively processes register definitions and calculates their absolute
317+
/// It recursively processes register definitions and calculates their absolute
318318
/// addresses based on a base pointer using byte offsets.
319319
#[doc(hidden)]
320320
#[macro_export]

src/ptr.rs

Lines changed: 122 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
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
66
use 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
}

tests/volatile_macro.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
21
#[test]
32
fn test_volatile_macro() {
43
use volatile_table::volatile;
5-
4+
65
let mut v = 10usize;
7-
let addr = &mut v as *mut _ as *mut usize;
6+
let addr = &mut v as *mut _;
87

98
unsafe {
109
// rw
@@ -33,4 +32,3 @@ fn test_volatile_macro() {
3332
assert_eq!(volatile_ptr.read(), 3);
3433
}
3534
}
36-

0 commit comments

Comments
 (0)