Skip to content

Commit 277b25b

Browse files
committed
Different rewrite approaches
1 parent 51855f4 commit 277b25b

File tree

6 files changed

+536
-185
lines changed

6 files changed

+536
-185
lines changed

src/access.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pub trait Readable {}
2+
pub trait Writable {}
3+
4+
pub struct Read;
5+
6+
impl Readable for Read {}
7+
8+
pub struct Write;
9+
impl Writable for Write {}
10+
11+
pub struct ReadWrite;
12+
impl Readable for ReadWrite {}
13+
impl Writable for ReadWrite {}

src/foo.rs

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
use crate::access::{ReadWrite, Readable, Writable};
2+
use core::{
3+
marker::PhantomData,
4+
ops::{Index, IndexMut},
5+
ptr,
6+
slice::SliceIndex,
7+
};
8+
9+
/// A wrapper type around a volatile variable, which allows for volatile reads and writes
10+
/// to the contained value. The stored type needs to be `Copy`, as volatile reads and writes
11+
/// take and return copies of the value.
12+
///
13+
/// The size of this struct is the same as the size of the contained type.
14+
#[derive(Debug, Default, Clone)]
15+
#[repr(transparent)]
16+
pub struct Volatile<T, A = ReadWrite> {
17+
value: T,
18+
access: PhantomData<A>,
19+
}
20+
21+
impl<T> Volatile<T> {
22+
/// Construct a new volatile instance wrapping the given value.
23+
///
24+
/// ```rust
25+
/// use volatile::Volatile;
26+
///
27+
/// let value = Volatile::new(0u32);
28+
/// ```
29+
///
30+
/// # Panics
31+
///
32+
/// This method never panics.
33+
pub const fn new(value: T) -> Volatile<T> {
34+
Volatile {
35+
value,
36+
access: PhantomData,
37+
}
38+
}
39+
}
40+
41+
impl<T: Copy, A> Volatile<&T, A> {
42+
/// Performs a volatile read of the contained value, returning a copy
43+
/// of the read value. Volatile reads are guaranteed not to be optimized
44+
/// away by the compiler, but by themselves do not have atomic ordering
45+
/// guarantees. To also get atomicity, consider looking at the `Atomic` wrapper type.
46+
///
47+
/// ```rust
48+
/// use volatile::Volatile;
49+
///
50+
/// let value = Volatile::new(42u32);
51+
///
52+
/// assert_eq!(value.read(), 42u32);
53+
/// ```
54+
///
55+
/// # Panics
56+
///
57+
/// This method never panics.
58+
pub fn read(&self) -> T
59+
where
60+
A: Readable,
61+
{
62+
// UNSAFE: Safe, as we know that our internal value exists.
63+
unsafe { ptr::read_volatile(self.value) }
64+
}
65+
}
66+
67+
impl<T: Copy, A> Volatile<&mut T, A> {
68+
/// Performs a volatile read of the contained value, returning a copy
69+
/// of the read value. Volatile reads are guaranteed not to be optimized
70+
/// away by the compiler, but by themselves do not have atomic ordering
71+
/// guarantees. To also get atomicity, consider looking at the `Atomic` wrapper type.
72+
///
73+
/// ```rust
74+
/// use volatile::Volatile;
75+
///
76+
/// let value = Volatile::new(42u32);
77+
///
78+
/// assert_eq!(value.read(), 42u32);
79+
/// ```
80+
///
81+
/// # Panics
82+
///
83+
/// This method never panics.
84+
pub fn read(&self) -> T
85+
where
86+
A: Readable,
87+
{
88+
// UNSAFE: Safe, as we know that our internal value exists.
89+
unsafe { ptr::read_volatile(self.value) }
90+
}
91+
92+
/// Performs a volatile write, setting the contained value to the given value `value`. Volatile
93+
/// writes are guaranteed to not be optimized away by the compiler, but by themselves do not
94+
/// have atomic ordering guarantees. To also get atomicity, consider looking at the `Atomic`
95+
/// wrapper type.
96+
///
97+
/// ```rust
98+
/// use volatile::Volatile;
99+
///
100+
/// let mut value = Volatile::new(0u32);
101+
///
102+
/// value.write(42u32);
103+
///
104+
/// assert_eq!(value.read(), 42u32);
105+
/// ```
106+
///
107+
/// # Panics
108+
///
109+
/// This method never panics.
110+
pub fn write(&mut self, value: T)
111+
where
112+
A: Writable,
113+
{
114+
// UNSAFE: Safe, as we know that our internal value exists.
115+
unsafe { ptr::write_volatile(self.value, value) };
116+
}
117+
118+
/// Performs a volatile read of the contained value, passes a mutable reference to it to the
119+
/// function `f`, and then performs a volatile write of the (potentially updated) value back to
120+
/// the contained value.
121+
///
122+
/// ```rust
123+
/// use volatile::Volatile;
124+
///
125+
/// let mut value = Volatile::new(21u32);
126+
///
127+
/// value.update(|val_ref| *val_ref *= 2);
128+
///
129+
/// assert_eq!(value.read(), 42u32);
130+
/// ```
131+
///
132+
/// # Panics
133+
///
134+
/// Ths method never panics.
135+
pub fn update<F>(&mut self, f: F)
136+
where
137+
F: FnOnce(&mut T),
138+
A: Readable + Writable,
139+
{
140+
let mut value = self.read();
141+
f(&mut value);
142+
self.write(value);
143+
}
144+
}
145+
146+
impl<T: Copy, A> Volatile<&[T], A> {
147+
pub fn index<I>(&self, index: I) -> Volatile<&I::Output, A>
148+
where
149+
I: SliceIndex<[T]>,
150+
{
151+
Volatile {
152+
value: self.value.index(index),
153+
access: self.access,
154+
}
155+
}
156+
}
157+
158+
impl<T: Copy, A> Volatile<&mut [T], A> {
159+
pub fn index<I>(&self, index: I) -> Volatile<&I::Output, A>
160+
where
161+
I: SliceIndex<[T]>,
162+
{
163+
Volatile {
164+
value: self.value.index(index),
165+
access: self.access,
166+
}
167+
}
168+
169+
pub fn index_mut<I>(&mut self, index: I) -> Volatile<&mut I::Output, A>
170+
where
171+
I: SliceIndex<[T]>,
172+
{
173+
Volatile {
174+
value: self.value.index_mut(index),
175+
access: self.access,
176+
}
177+
}
178+
}
179+
180+
#[cfg(test)]
181+
mod tests {
182+
use super::Volatile;
183+
184+
#[test]
185+
fn test_read() {
186+
let val = 42;
187+
assert_eq!(Volatile::new(&42).read(), 42);
188+
}
189+
190+
#[test]
191+
fn test_write() {
192+
let mut val = 50;
193+
let mut volatile = Volatile::new(&mut val);
194+
volatile.write(50);
195+
assert_eq!(val, 50);
196+
}
197+
198+
#[test]
199+
fn test_update() {
200+
let mut val = 42;
201+
let mut volatile = Volatile::new(&mut val);
202+
volatile.update(|v| *v += 1);
203+
assert_eq!(val, 43);
204+
}
205+
206+
#[test]
207+
fn test_slice() {
208+
let mut val = [1, 2, 3];
209+
let mut volatile = Volatile::new(&mut val[..]);
210+
volatile.index_mut(0).update(|v| *v += 1);
211+
assert_eq!(val, [2, 2, 3]);
212+
}
213+
}

0 commit comments

Comments
 (0)