Skip to main content

orx_concurrent_option/
with_order.rs

1use crate::{ConcurrentOption, states::*};
2use core::{ops::Deref, sync::atomic::Ordering};
3
4impl<T> ConcurrentOption<T> {
5    /// Loads and returns the concurrent state of the option with the given `order`.
6    ///
7    /// # Examples
8    ///
9    /// ```
10    /// use orx_concurrent_option::*;
11    /// use core::sync::atomic::Ordering;
12    ///
13    /// let x: ConcurrentOption<u32> = ConcurrentOption::some(2);
14    /// assert_eq!(x.state(Ordering::Relaxed), State::Some);
15    ///
16    /// let x: ConcurrentOption<u32> = ConcurrentOption::none();
17    /// assert_eq!(x.state(Ordering::SeqCst), State::None);
18    /// ```
19    pub fn state(&self, order: Ordering) -> State {
20        State::new(self.state.load(order))
21    }
22
23    /// Returns `true` if the option is a Some variant.
24    ///
25    /// # Examples
26    ///
27    /// ```
28    /// use orx_concurrent_option::*;
29    /// use core::sync::atomic::Ordering;
30    ///
31    /// let x: ConcurrentOption<u32> = ConcurrentOption::some(2);
32    /// assert_eq!(x.is_some(), true);
33    ///
34    /// let x: ConcurrentOption<u32> = ConcurrentOption::none();
35    /// assert_eq!(x.is_some(), false);
36    /// ```
37    #[inline]
38    pub fn is_some_with_order(&self, order: Ordering) -> bool {
39        self.state.load(order) == SOME
40    }
41
42    /// Returns `true` if the option is a None variant.
43    ///
44    /// # Examples
45    ///
46    /// ```
47    /// use orx_concurrent_option::*;
48    ///
49    /// let x: ConcurrentOption<u32> = ConcurrentOption::some(2);
50    /// assert_eq!(x.is_none(), false);
51    ///
52    /// let x: ConcurrentOption<u32> = ConcurrentOption::none();
53    /// assert_eq!(x.is_none(), true);
54    /// ```
55    #[inline]
56    pub fn is_none_with_order(&self, order: Ordering) -> bool {
57        self.state.load(order) != SOME
58    }
59
60    /// Converts from `&Option<T>` to `Option<&T>`.
61    ///
62    /// Depending on requirement of the use case, `Relaxed`, `Acquire` or `SeqCst` can be used as the `order`.
63    ///
64    /// # Safety
65    ///
66    /// Note that creating a valid reference part of this method is thread safe.
67    ///
68    /// The method is `unsafe` due to the returned reference to the underlying value.
69    ///
70    /// * It is safe to use this method if the returned reference is discarded (miri would still complain).
71    /// * It is also safe to use this method if the caller is able to guarantee that there exist
72    ///   no concurrent writes while holding onto this reference.
73    ///   * One such case is using `as_ref` together with `initialize_when_none` method.
74    ///     This is perfectly safe since the value will be written only once,
75    ///     and `as_ref` returns a valid reference only after the value is initialized.
76    /// * Otherwise, it will lead to an **Undefined Behavior** due to data race.
77    ///
78    /// # Examples
79    ///
80    /// ```rust
81    /// use orx_concurrent_option::*;
82    /// use core::sync::atomic::Ordering;
83    ///
84    /// let x = ConcurrentOption::some(3.to_string());
85    /// assert_eq!(unsafe { x.as_ref_with_order(Ordering::Relaxed) }, Some(&3.to_string()));
86    ///
87    /// _ = x.take();
88    /// assert_eq!(unsafe { x.as_ref_with_order(Ordering::Acquire) }, None);
89    /// ```
90    pub unsafe fn as_ref_with_order(&self, order: Ordering) -> Option<&T> {
91        match self.state.load(order) {
92            SOME => {
93                let x = unsafe { &*self.value.get() };
94                Some(unsafe { x.assume_init_ref() })
95            }
96            _ => None,
97        }
98    }
99
100    /// Converts from `Option<T>` (or `&Option<T>`) to `Option<&T::Target>`.
101    ///
102    /// Leaves the original Option in-place, creating a new one with a reference
103    /// to the original one, additionally coercing the contents via [`Deref`].
104    ///
105    /// Depending on requirement of the use case, `Relaxed`, `Acquire` or `SeqCst` can be used as the `order`.
106    ///
107    /// # Safety
108    ///
109    /// Note that creating a valid reference part of this method is thread safe.
110    ///
111    /// The method is `unsafe` due to the returned reference to the underlying value.
112    ///
113    /// * It is safe to use this method if the returned reference is discarded (miri would still complain).
114    /// * It is also safe to use this method if the caller is able to guarantee that there exist
115    ///   no concurrent writes while holding onto this reference.
116    ///   * One such case is using `as_ref` together with `initialize_when_none` method.
117    ///     This is perfectly safe since the value will be written only once,
118    ///     and `as_ref` returns a valid reference only after the value is initialized.
119    /// * Otherwise, it will lead to an **Undefined Behavior** due to data race.
120    ///
121    /// # Examples
122    ///
123    /// ```rust
124    /// use orx_concurrent_option::*;
125    /// use core::sync::atomic::Ordering;
126    ///
127    /// unsafe
128    /// {
129    ///     let x: ConcurrentOption<String> = ConcurrentOption::some("hey".to_owned());
130    ///     assert_eq!(x.as_deref_with_order(Ordering::Acquire), Some("hey"));
131    ///
132    ///     let x: ConcurrentOption<String> = ConcurrentOption::none();
133    ///     assert_eq!(x.as_deref_with_order(Ordering::SeqCst), None);
134    /// }
135    /// ```
136    pub unsafe fn as_deref_with_order(&self, order: Ordering) -> Option<&<T as Deref>::Target>
137    where
138        T: Deref,
139    {
140        match self.state.load(order) {
141            SOME => {
142                let x = unsafe { &*self.value.get() };
143                Some(unsafe { x.assume_init_ref() })
144            }
145            _ => None,
146        }
147    }
148
149    /// Returns an iterator over the possibly contained value; yields
150    ///
151    /// * the single element if the option is of Some variant;
152    /// * no elements otherwise.
153    ///
154    /// Depending on requirement of the use case, `Relaxed`, `Acquire` or `SeqCst` can be used as the `order`.
155    ///
156    /// # Safety
157    ///
158    /// Note that creating a valid reference part of this method is thread safe.
159    ///
160    /// The method is `unsafe` due to the returned reference to the underlying value.
161    ///
162    /// * It is safe to use this method if the returned reference is discarded (miri would still complain).
163    /// * It is also safe to use this method if the caller is able to guarantee that there exist
164    ///   no concurrent writes while holding onto this reference.
165    ///   * One such case is using `as_ref` together with `initialize_when_none` method.
166    ///     This is perfectly safe since the value will be written only once,
167    ///     and `as_ref` returns a valid reference only after the value is initialized.
168    /// * Otherwise, it will lead to an **Undefined Behavior** due to data race.
169    ///
170    /// # Examples
171    ///
172    /// ```rust
173    /// use orx_concurrent_option::*;
174    /// use core::sync::atomic::Ordering;
175    ///
176    /// fn validate<'a>(mut iter: impl ExactSizeIterator<Item = &'a String>) {
177    ///     assert_eq!(iter.len(), 0);
178    ///     assert!(iter.next().is_none());
179    ///     assert!(iter.next().is_none());
180    /// }
181    ///
182    /// let x = ConcurrentOption::<String>::none();
183    /// unsafe
184    /// {
185    /// validate(x.iter_with_order(Ordering::SeqCst));
186    ///     validate(x.iter_with_order(Ordering::Relaxed).rev());
187    ///     validate((&x).into_iter());
188    /// }
189    /// ```
190    pub unsafe fn iter_with_order(&self, order: Ordering) -> crate::iter::Iter<'_, T> {
191        let maybe = unsafe { self.as_ref_with_order(order) };
192        crate::iter::Iter {
193            maybe,
194            _handle: None,
195        }
196    }
197
198    /// Clones the concurrent option with the desired `order` into an Option.
199    ///
200    /// Note that the `Clone` trait implementation clones the concurrent option with the default ordering.
201    ///
202    /// You may use `clone_with_order` in order to clone with the desired ordering.
203    ///
204    /// ```rust
205    /// use orx_concurrent_option::*;
206    /// use core::sync::atomic::Ordering;
207    ///
208    /// let mut x = ConcurrentOption::some(42);
209    /// let y = x.clone_with_order(Ordering::SeqCst);
210    /// assert_eq!(x.take(), y);
211    /// ```
212    pub fn clone_with_order(&self, order: Ordering) -> Option<T>
213    where
214        T: Clone,
215    {
216        // hold the lock for the entire clone; `as_ref_with_order` provides no synchronization at all
217        let _ = order;
218        match self.spin_get_handle(SOME, SOME) {
219            Some(_handle) => {
220                let x = unsafe { (*self.value.get()).assume_init_ref() };
221                Some(x.clone())
222            }
223            None => None,
224        }
225    }
226
227    /// Returns whether or not self is equal to the `other` with the desired `order`.
228    ///
229    /// Note that the `PartialEq` trait implementation checks equality with the default ordering.
230    ///
231    /// You may use `eq_with_order` in order to check equality with the desired ordering.
232    ///
233    /// ```rust
234    /// use orx_concurrent_option::*;
235    /// use core::sync::atomic::Ordering;
236    ///
237    /// let x = ConcurrentOption::some(3);
238    /// let y = ConcurrentOption::some(7);
239    /// let z = ConcurrentOption::<i32>::none();
240    ///
241    /// let o = Ordering::SeqCst;
242    ///
243    /// assert!(x.eq_with_order(&x, o));
244    /// assert!(!x.eq_with_order(&y, o));
245    /// assert!(!x.eq_with_order(&z, o));
246    ///
247    /// assert!(!z.eq_with_order(&x, o));
248    /// assert!(!z.eq_with_order(&y, o));
249    /// assert!(z.eq_with_order(&z, o));
250    /// ```
251    pub fn eq_with_order(&self, other: &Self, order: Ordering) -> bool
252    where
253        T: PartialEq,
254    {
255        let _ = order;
256        self.locked_compare(other, true, false, false, |l, r| l.eq(r))
257    }
258
259    /// Returns an ordering between `self` and `other` with the desired `order`.
260    ///
261    /// Note that the `PartialOrd` trait implementation checks equality with the default ordering.
262    ///
263    /// You may use `partial_cmp_with_order` in order to check equality with the desired ordering.
264    ///
265    /// ```rust
266    /// use orx_concurrent_option::*;
267    /// use core::cmp::Ordering::*;
268    ///
269    /// let x = ConcurrentOption::some(3);
270    /// let y = ConcurrentOption::some(7);
271    /// let z = ConcurrentOption::<i32>::none();
272    ///
273    /// let ord = core::sync::atomic::Ordering::SeqCst;
274    ///
275    /// assert_eq!(x.partial_cmp_with_order(&x, ord), Some(Equal));
276    /// assert_eq!(x.partial_cmp_with_order(&y, ord), Some(Less));
277    /// assert_eq!(x.partial_cmp_with_order(&z, ord), Some(Greater));
278    ///
279    /// assert_eq!(y.partial_cmp_with_order(&x, ord), Some(Greater));
280    /// assert_eq!(y.partial_cmp_with_order(&y, ord), Some(Equal));
281    /// assert_eq!(y.partial_cmp_with_order(&z, ord), Some(Greater));
282    ///
283    /// assert_eq!(z.partial_cmp_with_order(&x, ord), Some(Less));
284    /// assert_eq!(z.partial_cmp_with_order(&y, ord), Some(Less));
285    /// assert_eq!(z.partial_cmp_with_order(&z, ord), Some(Equal));
286    /// ```
287    pub fn partial_cmp_with_order(
288        &self,
289        other: &Self,
290        order: Ordering,
291    ) -> Option<core::cmp::Ordering>
292    where
293        T: PartialOrd,
294    {
295        use core::cmp::Ordering::*;
296
297        let _ = order;
298        self.locked_compare(other, Some(Equal), Some(Greater), Some(Less), |l, r| {
299            l.partial_cmp(r)
300        })
301    }
302
303    /// Returns an ordering between `self` and `other` with the desired `order`.
304    ///
305    /// Note that the `Ord` trait implementation checks equality with the default ordering.
306    ///
307    /// You may use `cmp_with_order` in order to check equality with the desired ordering.
308    ///
309    /// ```rust
310    /// use orx_concurrent_option::*;
311    /// use core::cmp::Ordering::*;
312    ///
313    /// let x = ConcurrentOption::some(3);
314    /// let y = ConcurrentOption::some(7);
315    /// let z = ConcurrentOption::<i32>::none();
316    ///
317    /// let ord = core::sync::atomic::Ordering::SeqCst;
318    ///
319    /// assert_eq!(x.cmp_with_order(&x, ord), Equal);
320    /// assert_eq!(x.cmp_with_order(&y, ord), Less);
321    /// assert_eq!(x.cmp_with_order(&z, ord), Greater);
322    ///
323    /// assert_eq!(y.cmp_with_order(&x, ord), Greater);
324    /// assert_eq!(y.cmp_with_order(&y, ord), Equal);
325    /// assert_eq!(y.cmp_with_order(&z, ord), Greater);
326    ///
327    /// assert_eq!(z.cmp_with_order(&x, ord), Less);
328    /// assert_eq!(z.cmp_with_order(&y, ord), Less);
329    /// assert_eq!(z.cmp_with_order(&z, ord), Equal);
330    /// ```
331    pub fn cmp_with_order(&self, other: &Self, order: Ordering) -> core::cmp::Ordering
332    where
333        T: Ord,
334    {
335        use core::cmp::Ordering::*;
336
337        let _ = order;
338        self.locked_compare(other, Equal, Greater, Less, |l, r| l.cmp(r))
339    }
340}