orx_concurrent_vec/concurrent_slice/unsafe_api.rs
1use super::ConcurrentSlice;
2use crate::ConcurrentElement;
3use core::sync::atomic::Ordering;
4use orx_pinned_vec::IntoConcurrentPinnedVec;
5
6impl<T, P> ConcurrentSlice<'_, T, P>
7where
8 P: IntoConcurrentPinnedVec<ConcurrentElement<T>>,
9{
10 /// Returns:
11 /// * a raw `*const T` pointer to the underlying data if element at the `i`-th position is pushed,
12 /// * `None` otherwise.
13 ///
14 /// # Safety
15 ///
16 /// Please see below the safety guarantees and potential safety risks using the pointer obtained by this method.
17 ///
18 /// ## Safety Guarantees
19 ///
20 /// Pointer obtained by this method will be valid:
21 ///
22 /// * `ConcurrentVec` prevents access to elements which are not added yet.
23 /// * `ConcurrentOption` wrapper prevents access during initialization, and hence, prevents data race during initialization.
24 /// * `PinnedVec` storage makes sure that memory location of the elements never change.
25 ///
26 /// Therefore, the caller can hold on the obtained pointer throughout the lifetime of the vec.
27 /// It is guaranteed that it will be valid pointing to the correct position with initialized data.
28 ///
29 /// ## Unsafe Bits
30 ///
31 /// However, this method still leaks out a pointer, using which can cause data races as follows:
32 /// * The value of the position can be `replace`d or `set` or `update`d concurrently by another thread.
33 /// * If at the same instant, we attempt to read using this pointer, we would end up with a data-race.
34 ///
35 /// ## Safe Usage
36 ///
37 /// This method can be safely used as long as the caller is able to guarantee that the position will not be being mutated
38 /// while using the pointer to directly access the data.
39 ///
40 /// A common use case to this is the grow-only scenarios where added elements are not mutated:
41 /// * elements can be added to the vector by multiple threads,
42 /// * while already pushed elements can safely be accessed by other threads using `get_raw`.
43 pub fn get_raw(&self, i: usize) -> Option<*const T> {
44 self.idx(i).and_then(|i| self.vec.get_raw(i))
45 }
46
47 /// Returns a reference to the element at the `i`-th position of the vec.
48 /// It returns `None` if index is out of bounds.
49 ///
50 /// # Safety
51 ///
52 /// All methods that return `&T` or `&mut T` references are marked as unsafe.
53 /// Please see the reason and possible scenarios to use it safely below.
54 ///
55 /// ## Safety Guarantees
56 ///
57 /// Reference obtained by this method will be valid:
58 ///
59 /// * `ConcurrentVec` prevents access to elements which are not added yet.
60 /// * `ConcurrentOption` wrapper prevents access during initialization, and hence, prevents data race during initialization.
61 /// * `PinnedVec` storage makes sure that memory location of the elements never change.
62 ///
63 /// Therefore, the caller can hold on the obtained reference throughout the lifetime of the vec.
64 /// It is guaranteed that the reference will be valid pointing to the correct position.
65 ///
66 /// ## Unsafe Bits
67 ///
68 /// However, this method still leaks out a reference, which can cause data races as follows:
69 /// * The value of the position can be `replace`d or `set` or `update`d concurrently by another thread.
70 /// * If at the same instant, we attempt to read using this reference, we would end up with a data-race.
71 ///
72 /// ## Safe Usage
73 ///
74 /// This method can be safely used as long as the caller is able to guarantee that the position will not be being mutated
75 /// while using the reference to directly access the data.
76 ///
77 /// A common use case to this is the grow-only scenarios where added elements are not mutated:
78 /// * elements can be added to the vector by multiple threads,
79 /// * while already pushed elements can safely be accessed by other threads using `get`.
80 ///
81 /// # Examples
82 ///
83 /// As explained above, the following constructs a safe usage example of the unsafe get method.
84 ///
85 /// ```rust
86 /// use orx_concurrent_vec::*;
87 /// use std::time::Duration;
88 ///
89 /// #[derive(Debug, Default)]
90 /// struct Metric {
91 /// sum: i32,
92 /// count: i32,
93 /// }
94 ///
95 /// impl Metric {
96 /// fn aggregate(self, value: &i32) -> Self {
97 /// Self {
98 /// sum: self.sum + value,
99 /// count: self.count + 1,
100 /// }
101 /// }
102 /// }
103 ///
104 /// // record measurements in random intervals, roughly every 2ms
105 /// let measurements = ConcurrentVec::new();
106 ///
107 /// // collect metrics every 100 milliseconds
108 /// let metrics = ConcurrentVec::new();
109 ///
110 /// std::thread::scope(|s| {
111 /// // thread to store measurements as they arrive
112 /// s.spawn(|| {
113 /// for i in 0..100 {
114 /// std::thread::sleep(Duration::from_millis(i % 5));
115 ///
116 /// // collect measurements and push to measurements vec
117 /// measurements.push(i as i32);
118 /// }
119 /// });
120 ///
121 /// // thread to collect metrics every 100 milliseconds
122 /// s.spawn(|| {
123 /// for _ in 0..10 {
124 /// // safely read from measurements vec to compute the metric
125 /// // since pushed elements are not being mutated
126 /// let len = measurements.len();
127 /// let mut metric = Metric::default();
128 /// for i in 0..len {
129 /// if let Some(value) = unsafe { measurements.get_ref(i) } {
130 /// metric = metric.aggregate(value);
131 /// }
132 /// }
133 ///
134 /// // push result to metrics
135 /// metrics.push(metric);
136 ///
137 /// std::thread::sleep(Duration::from_millis(100));
138 /// }
139 /// });
140 /// });
141 ///
142 /// let measurements: Vec<_> = measurements.to_vec();
143 /// let averages: Vec<_> = metrics.to_vec();
144 ///
145 /// assert_eq!(measurements.len(), 100);
146 /// assert_eq!(averages.len(), 10);
147 /// ```
148 pub unsafe fn get_ref(&self, i: usize) -> Option<&T> {
149 self.idx(i).and_then(|i| unsafe { self.vec.get_ref(i) })
150 }
151
152 /// Returns an iterator to references of elements of the vec.
153 ///
154 /// See also [`iter`] and [`iter_cloned`] for thread-safe alternatives of concurrent access to elements.
155 ///
156 /// [`iter`]: crate::ConcurrentVec::iter
157 /// [`iter_cloned`]: crate::ConcurrentVec::iter_cloned
158 ///
159 /// # Safety
160 ///
161 /// All methods that return `&T` or `&mut T` references are marked as unsafe.
162 /// Please see the reason and possible scenarios to use it safely below.
163 ///
164 /// ## Safety Guarantees
165 ///
166 /// References obtained by this method will be valid:
167 ///
168 /// * `ConcurrentVec` prevents access to elements which are not added yet.
169 /// * `ConcurrentOption` wrapper prevents access during initialization, and hence, prevents data race during initialization.
170 /// * `PinnedVec` storage makes sure that memory location of the elements never change.
171 ///
172 /// Therefore, the caller can hold on the obtained references throughout the lifetime of the vec.
173 /// It is guaranteed that the references will be valid pointing to the correct positions.
174 ///
175 /// ## Unsafe Bits
176 ///
177 /// However, this method still leaks out references that can cause data races as follows:
178 /// * Values of elements in the vector can be concurrently mutated by methods such as `replace` or `update` by other threads.
179 /// * If at the same instant, we attempt to read using these references, we would end up with a data-race.
180 ///
181 /// ## Safe Usage
182 ///
183 /// This method can be safely used as long as the caller is able to guarantee that the position will not be being mutated
184 /// while using these references to directly access the data.
185 ///
186 /// A common use case to this is the grow-only scenarios where added elements are not mutated:
187 /// * elements can be added to the vector by multiple threads,
188 /// * while already pushed elements can safely be accessed by other threads using `iter`.
189 ///
190 /// # Examples
191 ///
192 /// As explained above, the following constructs a safe usage example of the unsafe iter method.
193 ///
194 /// ```rust
195 /// use orx_concurrent_vec::*;
196 /// use std::time::Duration;
197 ///
198 /// #[derive(Debug, Default)]
199 /// struct Metric {
200 /// sum: i32,
201 /// count: i32,
202 /// }
203 ///
204 /// impl Metric {
205 /// fn aggregate(self, value: &i32) -> Self {
206 /// Self {
207 /// sum: self.sum + value,
208 /// count: self.count + 1,
209 /// }
210 /// }
211 /// }
212 ///
213 /// // record measurements in random intervals, roughly every 2ms
214 /// let measurements = ConcurrentVec::new();
215 ///
216 /// // collect metrics every 100 milliseconds
217 /// let metrics = ConcurrentVec::new();
218 ///
219 /// std::thread::scope(|s| {
220 /// // thread to store measurements as they arrive
221 /// s.spawn(|| {
222 /// for i in 0..100 {
223 /// std::thread::sleep(Duration::from_millis(i % 5));
224 ///
225 /// // collect measurements and push to measurements vec
226 /// measurements.push(i as i32);
227 /// }
228 /// });
229 ///
230 /// // thread to collect metrics every 100 milliseconds
231 /// s.spawn(|| {
232 /// for _ in 0..10 {
233 /// // safely read from measurements vec to compute the metric
234 /// // since pushed elements are never mutated
235 /// let metric = unsafe {
236 /// measurements
237 /// .iter_ref()
238 /// .fold(Metric::default(), |x, value| x.aggregate(value))
239 /// };
240 ///
241 /// // push result to metrics
242 /// metrics.push(metric);
243 ///
244 /// std::thread::sleep(Duration::from_millis(100));
245 /// }
246 /// });
247 /// });
248 ///
249 /// let measurements: Vec<_> = measurements.to_vec();
250 /// let averages: Vec<_> = metrics.to_vec();
251 ///
252 /// assert_eq!(measurements.len(), 100);
253 /// assert_eq!(averages.len(), 10);
254 /// ```
255 pub unsafe fn iter_ref(&self) -> impl Iterator<Item = &T> {
256 let b = self.a + self.len;
257 unsafe { self.vec.core.iter_over_range(self.a..b) }
258 .flat_map(|x| unsafe { x.0.as_ref_with_order(Ordering::SeqCst) })
259 }
260
261 // mut
262
263 /// Returns:
264 /// * a raw `*mut T` pointer to the underlying data if element at the `i`-th position is pushed,
265 /// * `None` otherwise.
266 ///
267 /// # Safety
268 ///
269 /// Please see below the safety guarantees and potential safety risks using the pointer obtained by this method.
270 ///
271 /// ## Safety Guarantees
272 ///
273 /// Pointer obtained by this method will be valid:
274 ///
275 /// * `ConcurrentVec` prevents access to elements which are not added yet.
276 /// * `ConcurrentOption` wrapper prevents access during initialization, and hence, prevents data race during initialization.
277 /// * `PinnedVec` storage makes sure that memory location of the elements never change.
278 ///
279 /// Therefore, the caller can hold on the obtained pointer throughout the lifetime of the vec.
280 /// It is guaranteed that it will be valid pointing to the correct position with initialized data.
281 ///
282 /// ## Unsafe Bits
283 ///
284 /// However, this method still leaks out a pointer, using which can cause data races as follows:
285 /// * The value of the position can be `replace`d or `set` or `update`d concurrently by another thread.
286 /// * If at the same instant, we attempt to read using this pointer, we would end up with a data-race.
287 ///
288 /// ## Safe Usage
289 ///
290 /// This method can be safely used as long as the caller is able to guarantee that the position will not be being
291 /// read or written by another thread while using the pointer to directly access the data.
292 pub fn get_raw_mut(&self, i: usize) -> Option<*mut T> {
293 self.idx(i).and_then(|i| self.vec.get_raw_mut(i))
294 }
295
296 /// Returns a mutable reference to the element at the `i`-th position of the vec.
297 /// It returns `None` if index is out of bounds.
298 ///
299 /// See also [`get`] and [`swap`] for thread-safe alternatives of concurrent mutation of elements.
300 ///
301 /// [`get`]: crate::ConcurrentVec::get
302 /// [`swap`]: crate::ConcurrentVec::swap
303 ///
304 /// # Safety
305 ///
306 /// All methods that leak out `&T` or `&mut T` references are marked as unsafe.
307 /// Please see the reason and possible scenarios to use it safely below.
308 ///
309 /// ## Safety Guarantees
310 ///
311 /// Reference obtained by this method will be valid:
312 ///
313 /// * `ConcurrentVec` prevents access to elements which are not added yet.
314 /// * `ConcurrentOption` wrapper prevents access during initialization, and hence, prevents data race during initialization.
315 /// * `PinnedVec` storage makes sure that memory location of the elements never change.
316 ///
317 /// Therefore, the caller can hold on the obtained reference throughout the lifetime of the vec.
318 /// It is guaranteed that the reference will be valid pointing to the correct position.
319 ///
320 /// ## Unsafe Bits
321 ///
322 /// However, this method still leaks out a reference, which can cause data races as follows:
323 /// * The value of the position can be `replace`d or `set` or `update`d concurrently by another thread.
324 /// * And it maybe read by safe access methods such as `map` or `cloned`.
325 /// * If at the same instant, we attempt to read or write using this reference, we would end up with a data-race.
326 ///
327 /// ## Safe Usage
328 ///
329 /// This method can be safely used as long as the caller is able to guarantee that the position will not be being
330 /// read or written by another thread while using the reference to directly access the data.
331 ///
332 /// # Examples
333 ///
334 /// ```rust
335 /// use orx_concurrent_vec::*;
336 ///
337 /// let vec = ConcurrentVec::new();
338 /// vec.extend(['a', 'b', 'c', 'd']);
339 ///
340 /// assert_eq!(unsafe { vec.get_mut(4) }, None);
341 ///
342 /// *unsafe { vec.get_mut(1).unwrap() } = 'x';
343 /// assert_eq!(unsafe { vec.get_ref(1) }, Some(&'x'));
344 ///
345 /// assert_eq!(&vec, &['a', 'x', 'c', 'd']);
346 /// ```
347 #[allow(clippy::mut_from_ref)]
348 pub unsafe fn get_mut(&self, i: usize) -> Option<&mut T> {
349 self.idx(i).and_then(|i| unsafe { self.vec.get_mut(i) })
350 }
351
352 /// Returns an iterator to mutable references of elements of the vec.
353 ///
354 /// See also [`iter`], [`fill`] and [`fill_with`] for thread-safe alternatives of concurrent mutation of elements.
355 ///
356 /// [`iter`]: crate::ConcurrentVec::iter
357 /// [`fill`]: crate::ConcurrentVec::fill
358 /// [`fill_with`]: crate::ConcurrentVec::fill_with
359 ///
360 /// # Safety
361 ///
362 /// All methods that leak out `&T` or `&mut T` references are marked as unsafe.
363 /// Please see the reason and possible scenarios to use it safely below.
364 ///
365 /// ## Safety Guarantees
366 ///
367 /// References obtained by this method will be valid:
368 ///
369 /// * `ConcurrentVec` prevents access to elements which are not added yet.
370 /// * `ConcurrentOption` wrapper prevents access during initialization, and hence, prevents data race during initialization.
371 /// * `PinnedVec` storage makes sure that memory location of the elements never change.
372 ///
373 /// Therefore, the caller can hold on the obtained references throughout the lifetime of the vec.
374 /// It is guaranteed that the references will be valid pointing to the correct position.
375 ///
376 /// ## Unsafe Bits
377 ///
378 /// However, this method still leaks out references, which can cause data races as follows:
379 /// * Values of elements can be concurrently read by other threads.
380 /// * Likewise, they can be concurrently mutated by thread-safe mutation methods.
381 /// * If at the same instant, we attempt to read or write using these references, we would end up with a data-race.
382 ///
383 /// ## Safe Usage
384 ///
385 /// This method can be safely used as long as the caller is able to guarantee that the elements will not be being
386 /// read or written by another thread while using the reference to directly access the data.
387 ///
388 /// # Examples
389 ///
390 /// ```rust
391 /// use orx_concurrent_vec::*;
392 ///
393 /// let vec = ConcurrentVec::from_iter([0, 1, 2, 3]);
394 ///
395 /// let iter = unsafe { vec.iter_mut() };
396 /// for x in iter {
397 /// *x *= 2;
398 /// }
399 ///
400 /// assert_eq!(&vec, &[0, 2, 4, 6]);
401 /// ```
402 pub unsafe fn iter_mut(&self) -> impl Iterator<Item = &mut T> {
403 let b = self.a + self.len;
404 unsafe { self.vec.core.iter_over_range(self.a..b) }
405 .flat_map(|x| x.0.get_raw_mut().map(|p| unsafe { &mut *p }))
406 }
407}