write_only/slice/
volatile.rs1use core::{marker::PhantomData, mem, ptr};
6
7use crate::{WriteAt, WriteFromSliceAt};
8
9pub struct VolatileWriteOnlySlice<'a, T: 'a> {
11 data: *mut T,
12 len: usize,
13 _phantom: PhantomData<&'a T>,
14}
15
16impl<'a, T: 'a> VolatileWriteOnlySlice<'a, T> {
17 #[inline]
54 pub unsafe fn from_raw_parts(data: *mut T, len: usize) -> Self {
55 debug_assert!(
56 !data.is_null() && (data.align_offset(mem::align_of::<u16>()) == 0),
57 "attempt to create unaligned or null slice"
58 );
59 debug_assert!(
60 mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
61 "attempt to create slice covering at least half the address space"
62 );
63 Self {
65 data,
66 len,
67 _phantom: PhantomData,
68 }
69 }
70
71 #[inline]
72 pub fn len(&self) -> usize {
73 self.len
74 }
75
76 #[inline]
77 pub fn is_empty(&self) -> bool {
78 self.len == 0
79 }
80}
81
82impl<'a, T: 'a> WriteAt<T> for VolatileWriteOnlySlice<'a, T> {
83 #[inline]
84 fn write_at(&mut self, index: usize, value: T) {
85 assert!(index < self.len);
86
87 unsafe {
88 self.write_at_unchecked(index, value);
89 }
90 }
91
92 #[inline]
93 unsafe fn write_at_unchecked(&mut self, index: usize, value: T) {
94 self.data.add(index).write_volatile(value);
95 }
96}
97
98impl<'a, T: 'a> WriteFromSliceAt<T> for VolatileWriteOnlySlice<'a, T> {
99 #[inline]
100 fn write_cloning_from_slice_at(&mut self, src: &[T], offset: usize)
101 where
102 T: Clone,
103 {
104 assert!(offset + src.len() <= self.len);
105
106 for (index, item) in src.iter().enumerate() {
111 unsafe {
112 self.data.add(offset + index).write_volatile(item.clone());
113 }
114 }
115 }
116
117 #[inline]
118 fn write_copying_from_slice_at(&mut self, src: &[T], offset: usize)
119 where
120 T: Copy,
121 {
122 assert!(src.len() <= self.len - offset);
123
124 unsafe {
128 #[cfg(feature = "core_intrinsics")]
132 core::intrinsics::volatile_copy_nonoverlapping_memory(
133 self.data,
134 src.as_ptr(),
135 src.len(),
136 );
137
138 #[cfg(not(feature = "core_intrinsics"))]
139 {
140 let dst_ptr = self.data.add(offset);
141 for (index, item) in src.iter().enumerate() {
142 ptr::write_volatile(dst_ptr.add(index), *item);
143 }
144 }
145 }
146 }
147}
148
149impl<'a, T: 'a> From<&'a mut [T]> for VolatileWriteOnlySlice<'a, T> {
150 #[inline]
151 fn from(slice: &'a mut [T]) -> Self {
152 unsafe { Self::from_raw_parts(slice.as_mut_ptr(), slice.len()) }
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159
160 use droptest::prelude::*;
161
162 #[test]
163 fn from_raw_parts() {
164 let registry = DropRegistry::default();
165 let mut guards: Vec<_> = (0..3).map(|i| registry.new_guard_for(i)).collect();
166
167 let reference = unsafe { VolatileWriteOnlySlice::from_raw_parts(&mut guards, 3) };
168
169 std::mem::drop(reference);
170
171 assert_drop_stats!(registry, { created: 3, dropped: 0 });
172
173 std::mem::drop(guards);
174
175 assert_drop_stats!(registry, { created: 3, dropped: 3 });
176 }
177
178 #[test]
179 fn from() {
180 let registry = DropRegistry::default();
181 let mut guards: Vec<_> = (0..3).map(|i| registry.new_guard_for(i)).collect();
182
183 let reference = VolatileWriteOnlySlice::from(&mut guards[..]);
184
185 std::mem::drop(reference);
186
187 assert_drop_stats!(registry, { created: 3, dropped: 0 });
188
189 std::mem::drop(guards);
190
191 assert_drop_stats!(registry, { created: 3, dropped: 3 });
192 }
193
194 #[test]
195 fn write_at() {
196 let registry = DropRegistry::default();
197 let (old_ids, mut guards): (Vec<_>, Vec<_>) =
198 (0..3).map(|i| registry.new_guard_for(i).by_id()).unzip();
199 let (new_id, new_guard) = registry.new_guard_for(3).by_id();
200
201 let mut slice = VolatileWriteOnlySlice::from(&mut guards[..]);
202 slice.write_at(1, new_guard);
203
204 assert_eq!(guards[1].id(), new_id);
205 assert_eq!(guards[1].value(), &3);
206
207 assert_no_drop!(registry, old_ids[1]);
208 assert_drop_stats!(registry, { created: 4, dropped: 0 });
209 }
210
211 #[test]
212 #[should_panic]
213 fn write_at_out_of_bounds() {
214 let registry = DropRegistry::default();
215 let mut guards: Vec<_> = (0..3).map(|i| registry.new_guard_for(i)).collect();
216 let new_guard = registry.new_guard_for(3);
217
218 let mut slice = VolatileWriteOnlySlice::from(&mut guards[..]);
219 slice.write_at(10, new_guard);
220 }
221
222 #[test]
223 fn write_cloning_from_slice_at() {
224 let registry = DropRegistry::default();
225 let (old_ids, mut guards): (Vec<_>, Vec<_>) =
226 (0..5).map(|i| registry.new_guard_for(i).by_id()).unzip();
227 let new_guards: Vec<_> = (5..8).map(|i| registry.new_guard_for(i)).collect();
228
229 let mut slice = VolatileWriteOnlySlice::from(&mut guards[..]);
230 slice.write_cloning_from_slice_at(&new_guards[..], 1);
231
232 assert_ne!(guards[1].id(), old_ids[1]);
233 assert_eq!(guards[1].value(), &5);
234 assert_ne!(guards[2].id(), old_ids[1]);
235 assert_eq!(guards[2].value(), &6);
236 assert_ne!(guards[3].id(), old_ids[2]);
237 assert_eq!(guards[3].value(), &7);
238
239 assert_no_drop!(registry, old_ids[1]);
240 assert_no_drop!(registry, old_ids[2]);
241 assert_no_drop!(registry, old_ids[3]);
242 assert_drop_stats!(registry, { created: 11, dropped: 0 });
243 }
244
245 #[test]
246 fn write_copying_from_slice_at() {
247 let mut values: Vec<_> = (0..5).collect();
248 let new_values: Vec<_> = (5..8).collect();
249
250 let mut slice = VolatileWriteOnlySlice::from(&mut values[..]);
251 slice.write_copying_from_slice_at(&new_values[..], 1);
252
253 assert_eq!(values, &[0, 5, 6, 7, 4]);
254 }
255}