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}