Skip to main content

orx_concurrent_option/
option.rs

1use crate::{IntoOption, concurrent_option::ConcurrentOption, states::*};
2use core::sync::atomic::Ordering;
3use core::{mem::MaybeUninit, ops::Deref};
4
5impl<T> ConcurrentOption<T> {
6    // &self
7
8    /// Returns `true` if the option is a Some variant.
9    ///
10    /// # Examples
11    ///
12    /// ```
13    /// use orx_concurrent_option::*;
14    /// use core::sync::atomic::Ordering;
15    ///
16    /// let x: ConcurrentOption<u32> = ConcurrentOption::some(2);
17    /// assert_eq!(x.is_some(), true);
18    ///
19    /// let x: ConcurrentOption<u32> = ConcurrentOption::none();
20    /// assert_eq!(x.is_some(), false);
21    /// ```
22    #[inline]
23    pub fn is_some(&self) -> bool {
24        self.state.load(Ordering::Relaxed) == SOME
25    }
26
27    /// Returns `true` if the option is a None variant.
28    ///
29    /// # Examples
30    ///
31    /// ```
32    /// use orx_concurrent_option::*;
33    ///
34    /// let x: ConcurrentOption<u32> = ConcurrentOption::some(2);
35    /// assert_eq!(x.is_none(), false);
36    ///
37    /// let x: ConcurrentOption<u32> = ConcurrentOption::none();
38    /// assert_eq!(x.is_none(), true);
39    /// ```
40    #[inline]
41    pub fn is_none(&self) -> bool {
42        self.state.load(Ordering::Relaxed) != SOME
43    }
44
45    /// Partially thread safe method to convert from `&Option<T>` to `Option<&T>`.
46    ///
47    /// # Safety
48    ///
49    /// Note that creating a valid reference part of this method is thread safe.
50    ///
51    /// The method is `unsafe` due to the returned reference to the underlying value.
52    ///
53    /// * It is safe to use this method if the returned reference is discarded (miri would still complain).
54    /// * It is also safe to use this method if the caller is able to guarantee that there exist
55    ///   no concurrent writes while holding onto this reference.
56    ///   * One such case is using `as_ref` together with `initialize_when_none` method.
57    ///     This is perfectly safe since the value will be written only once,
58    ///     and `as_ref` returns a valid reference only after the value is initialized.
59    /// * Otherwise, it will lead to an **Undefined Behavior** due to data race.
60    ///
61    /// # Examples
62    ///
63    /// ```rust
64    /// use orx_concurrent_option::*;
65    ///
66    /// let x = ConcurrentOption::some(3.to_string());
67    /// assert_eq!(unsafe { x.as_ref() }, Some(&3.to_string()));
68    ///
69    /// _ = x.take();
70    /// assert_eq!(unsafe { x.as_ref() }, None);
71    /// ```
72    pub unsafe fn as_ref(&self) -> Option<&T> {
73        match self.spin_get_handle(SOME, SOME) {
74            Some(_handle) => {
75                let x = unsafe { &*self.value.get() };
76                Some(unsafe { x.assume_init_ref() })
77            }
78            None => None,
79        }
80    }
81
82    /// Partially thread safe method to convert from `Option<T>` (or `&Option<T>`) to `Option<&T::Target>`.
83    ///
84    /// Leaves the original Option in-place, creating a new one with a reference
85    /// to the original one, additionally coercing the contents via [`Deref`].
86    ///
87    /// # Safety
88    ///
89    /// Note that creating a valid reference part of this method is thread safe.
90    ///
91    /// The method is `unsafe` due to the returned reference to the underlying value.
92    ///
93    /// * It is safe to use this method if the returned reference is discarded (miri would still complain).
94    /// * It is also safe to use this method if the caller is able to guarantee that there exist
95    ///   no concurrent writes while holding onto this reference.
96    ///   * One such case is using `as_ref` together with `initialize_when_none` method.
97    ///     This is perfectly safe since the value will be written only once,
98    ///     and `as_ref` returns a valid reference only after the value is initialized.
99    /// * Otherwise, it will lead to an **Undefined Behavior** due to data race.
100    ///
101    /// # Examples
102    ///
103    /// ```rust
104    /// use orx_concurrent_option::*;
105    ///
106    /// let x: ConcurrentOption<String> = ConcurrentOption::some("hey".to_owned());
107    /// assert_eq!(unsafe { x.as_deref() }, Some("hey"));
108    ///
109    /// let x: ConcurrentOption<String> = ConcurrentOption::none();
110    /// assert_eq!(unsafe { x.as_deref() }, None);
111    /// ```
112    pub unsafe fn as_deref(&self) -> Option<&<T as Deref>::Target>
113    where
114        T: Deref,
115    {
116        match self.spin_get_handle(SOME, SOME) {
117            Some(_handle) => {
118                let x = unsafe { &*self.value.get() };
119                Some(unsafe { x.assume_init_ref() })
120            }
121            None => None,
122        }
123    }
124
125    /// Partially thread safe method to return an iterator over the possibly contained value; yields
126    /// * the single element if the option is of Some variant;
127    /// * no elements otherwise.
128    ///
129    /// # Safety
130    ///
131    /// Note that creating a valid reference part of this method is thread safe.
132    ///
133    /// The method is `unsafe` due to the returned reference to the underlying value.
134    ///
135    /// * It is safe to use this method if the returned reference is discarded (miri would still complain).
136    /// * It is also safe to use this method if the caller is able to guarantee that there exist
137    ///   no concurrent writes while holding onto this reference.
138    ///   * One such case is using `as_ref` together with `initialize_when_none` method.
139    ///     This is perfectly safe since the value will be written only once,
140    ///     and `as_ref` returns a valid reference only after the value is initialized.
141    /// * Otherwise, it will lead to an **Undefined Behavior** due to data race.
142    ///
143    /// # Examples
144    ///
145    /// ```rust
146    /// use orx_concurrent_option::*;
147    ///
148    /// fn validate<'a>(mut iter: impl ExactSizeIterator<Item = &'a String>) {
149    ///     assert_eq!(iter.len(), 0);
150    ///     assert!(iter.next().is_none());
151    ///     assert!(iter.next().is_none());
152    /// }
153    ///
154    /// let x = ConcurrentOption::<String>::none();
155    /// validate(unsafe { x.iter() });
156    /// validate(unsafe { x.iter() }.rev());
157    /// validate((&x).into_iter());
158    /// ```
159    pub unsafe fn iter(&self) -> crate::iter::Iter<'_, T> {
160        crate::iter::Iter {
161            maybe: unsafe { self.as_ref() },
162            _handle: None,
163        }
164    }
165
166    /// Clones the value of the `ConcurrentOption<T>` into a `Some` of `T`
167    /// if the concurrent option is some; returns None otherwise.
168    ///
169    /// # Examples
170    ///
171    /// ```
172    /// use orx_concurrent_option::*;
173    ///
174    /// let opt = ConcurrentOption::some(12);
175    /// assert_eq!(unsafe { opt.as_ref() }, Some(&12));
176    ///
177    /// let clone = opt.clone_into_option();
178    /// assert_eq!(clone, Some(12));
179    /// ```
180    pub fn clone_into_option(&self) -> Option<T>
181    where
182        T: Clone,
183    {
184        match self.spin_get_handle(SOME, SOME) {
185            Some(_handle) => {
186                let x = unsafe { &*self.value.get() };
187                Some(unsafe { x.assume_init_ref().clone() })
188            }
189            None => None,
190        }
191    }
192
193    /// Thread safe method to map the reference of the underlying value with the given function `f`.
194    ///
195    /// Returns
196    /// * None if the option is None
197    /// * `f(&value)` if the option is Some(value)
198    ///
199    /// # Concurrency Notes
200    ///
201    /// Notice that `map` is a composition of `as_ref` and `map`.
202    /// However, it is stronger in terms of thread safety since the access to the value is controlled
203    /// and a reference to the underlying value is not leaked outside the option.
204    ///
205    /// Therefore, `map` must be preferred in a concurrent program:
206    /// * the map operation via `map` guarantees that the underlying value will not be updated before the operation; while
207    /// * the alternative approach with `as_ref` is subject to data race if the state of the optional is concurrently being
208    ///   updated by methods such as `take`.
209    ///   * an exception to this is the `initialize_if_none` method which fits very well the initialize-once scenarios;
210    ///     here, `as_ref` and `initialize_if_none` can safely be called concurrently from multiple threads.
211    ///
212    /// # Examples
213    ///
214    /// ```rust
215    /// use orx_concurrent_option::*;
216    ///
217    /// let x = ConcurrentOption::<String>::none();
218    /// let len = x.map(|x| x.len());
219    /// assert_eq!(len, None);
220    ///
221    /// let x = ConcurrentOption::some("foo".to_string());
222    /// let len = x.map(|x| x.len());
223    /// assert_eq!(len, Some(3));
224    /// ```
225    pub fn map<U, F>(&self, f: F) -> Option<U>
226    where
227        F: FnOnce(&T) -> U,
228    {
229        match self.spin_get_handle(SOME, SOME) {
230            Some(_handle) => {
231                let x = unsafe { MaybeUninit::assume_init_ref(&*self.value.get()) };
232                Some(f(x))
233            }
234            None => None,
235        }
236    }
237
238    /// Returns the provided default result (if none),
239    /// or applies a function to the contained value (if any).
240    ///
241    /// Arguments passed to `map_or` are eagerly evaluated; if you are passing
242    /// the result of a function call, it is recommended to use [`map_or_else`],
243    /// which is lazily evaluated.
244    ///
245    /// [`map_or_else`]: ConcurrentOption::map_or_else
246    ///
247    /// # Examples
248    ///
249    /// ```
250    /// use orx_concurrent_option::*;
251    ///
252    /// let x = ConcurrentOption::some("foo");
253    /// assert_eq!(x.map_or(42, |v| v.len()), 3);
254    ///
255    /// let x: ConcurrentOption<&str> = ConcurrentOption::none();
256    /// assert_eq!(x.map_or(42, |v| v.len()), 42);
257    /// ```
258    pub fn map_or<U, F>(&self, default: U, f: F) -> U
259    where
260        F: FnOnce(&T) -> U,
261    {
262        match self.spin_get_handle(SOME, SOME) {
263            Some(_handle) => {
264                let x = unsafe { MaybeUninit::assume_init_ref(&*self.value.get()) };
265                f(x)
266            }
267            None => default,
268        }
269    }
270
271    /// Computes a default function result (if none), or
272    /// applies a different function to the contained value (if any).
273    ///
274    /// # Basic examples
275    ///
276    /// ```
277    /// use orx_concurrent_option::*;
278    ///
279    /// let k = 21;
280    ///
281    /// let x = ConcurrentOption::some("foo");
282    /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
283    ///
284    /// let x: ConcurrentOption<&str> = ConcurrentOption::none();
285    /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
286    /// ```
287    pub fn map_or_else<U, D, F>(&self, default: D, f: F) -> U
288    where
289        D: FnOnce() -> U,
290        F: FnOnce(&T) -> U,
291    {
292        match self.spin_get_handle(SOME, SOME) {
293            Some(_handle) => {
294                let x = unsafe { MaybeUninit::assume_init_ref(&*self.value.get()) };
295                f(x)
296            }
297            None => default(),
298        }
299    }
300
301    /// Thread safe method that returns `true` if the option is a Some and the value inside of it matches a predicate.
302    ///
303    /// # Examples
304    ///
305    /// ```
306    /// use orx_concurrent_option::*;
307    ///
308    /// let x = ConcurrentOption::some(2);
309    /// assert_eq!(x.is_some_and(|x| *x > 1), true);
310    ///
311    /// let x = ConcurrentOption::some(0);
312    /// assert_eq!(x.is_some_and(|x| *x > 1), false);
313    ///
314    /// let x: ConcurrentOption<i32> = ConcurrentOption::none();
315    /// assert_eq!(x.is_some_and(|x| *x > 1), false);
316    /// ```
317    #[inline]
318    pub fn is_some_and(&self, f: impl FnOnce(&T) -> bool) -> bool {
319        match self.spin_get_handle(SOME, SOME) {
320            Some(_handle) => {
321                let x = unsafe { MaybeUninit::assume_init_ref(&*self.value.get()) };
322                f(x)
323            }
324            None => false,
325        }
326    }
327
328    /// Returns None if the option is None, otherwise returns `other`.
329    ///
330    /// Arguments passed to `and` are eagerly evaluated; if you are passing the
331    /// result of a function call, it is recommended to use [`and_then`], which is
332    /// lazily evaluated.
333    ///
334    /// [`and_then`]: ConcurrentOption::and_then
335    ///
336    /// # Examples
337    ///
338    /// ```
339    /// use orx_concurrent_option::*;
340    ///
341    /// let x = ConcurrentOption::some(2);
342    /// let y: ConcurrentOption<&str> = ConcurrentOption::none();
343    /// assert_eq!(x.and(y), None);
344    ///
345    /// let x: ConcurrentOption<u32> = ConcurrentOption::none();
346    /// let y = ConcurrentOption::some("foo");
347    /// assert_eq!(x.and(y), None);
348    ///
349    /// let x = ConcurrentOption::some(2);
350    /// let y = Some("foo");
351    /// assert_eq!(x.and(y), Some("foo"));
352    ///
353    /// let x: ConcurrentOption<u32> = ConcurrentOption::none();
354    /// let y: Option<&str> = None;
355    /// assert_eq!(x.and(y), None);
356    /// ```
357    pub fn and<U>(&self, other: impl IntoOption<U>) -> Option<U> {
358        match self.is_some() {
359            true => other.into_option(),
360            false => None,
361        }
362    }
363
364    /// Returns None if the option is None, otherwise calls `f` with the
365    /// wrapped value and returns the result.
366    ///
367    /// Some languages call this operation flatmap.
368    ///
369    /// # Examples
370    ///
371    /// ```
372    /// use orx_concurrent_option::*;
373    ///
374    /// fn sq_then_to_string(x: &u32) -> Option<String> {
375    ///     x.checked_mul(*x).map(|sq| sq.to_string())
376    /// }
377    ///
378    /// assert_eq!(ConcurrentOption::some(2).and_then(sq_then_to_string), Some(4.to_string()));
379    /// assert_eq!(ConcurrentOption::some(1_000_000).and_then(sq_then_to_string), None); // overflowed!
380    /// assert_eq!(ConcurrentOption::none().and_then(sq_then_to_string), None);
381    /// ```
382    ///
383    /// Since `ConcurrentOption` also implements `IntoOption`; and_then can also be called with
384    /// a function returning a concurrent option.
385    ///
386    /// ```
387    /// use orx_concurrent_option::*;
388    ///
389    /// fn sq_then_to_string(x: &u32) -> ConcurrentOption<String> {
390    ///     x.checked_mul(*x).map(|sq| sq.to_string()).into()
391    /// }
392    ///
393    /// assert_eq!(ConcurrentOption::some(2).and_then(sq_then_to_string), Some(4.to_string()));
394    /// assert_eq!(ConcurrentOption::some(1_000_000).and_then(sq_then_to_string), None); // overflowed!
395    /// assert_eq!(ConcurrentOption::none().and_then(sq_then_to_string), None);
396    /// ```
397    pub fn and_then<U, V, F>(&self, f: F) -> Option<U>
398    where
399        V: IntoOption<U>,
400        F: FnOnce(&T) -> V,
401    {
402        match self.spin_get_handle(SOME, SOME) {
403            Some(_handle) => {
404                let x = unsafe { MaybeUninit::assume_init_ref(&*self.value.get()) };
405                f(x).into_option()
406            }
407            None => None,
408        }
409    }
410
411    /// Returns None if the option is None, otherwise calls `predicate`
412    /// with the wrapped value and returns:
413    ///
414    /// - Some(t) if `predicate` returns `true` (where `t` is the wrapped
415    ///   value), and
416    /// - None if `predicate` returns `false`.
417    ///
418    /// This function works similar to [`Iterator::filter()`]. You can imagine
419    /// the `Option<T>` being an iterator over one or zero elements. `filter()`
420    /// lets you decide which elements to keep.
421    ///
422    /// # Safety
423    ///
424    /// Note that creating a valid reference part of this method is thread safe.
425    ///
426    /// The method is `unsafe` due to the returned reference to the underlying value.
427    ///
428    /// * It is safe to use this method if the returned reference is discarded (miri would still complain).
429    /// * It is also safe to use this method if the caller is able to guarantee that there exist
430    ///   no concurrent writes while holding onto this reference.
431    ///   * One such case is using `as_ref` together with `initialize_when_none` method.
432    ///     This is perfectly safe since the value will be written only once,
433    ///     and `as_ref` returns a valid reference only after the value is initialized.
434    /// * Otherwise, it will lead to an **Undefined Behavior** due to data race.
435    ///
436    /// # Examples
437    ///
438    /// ```rust
439    /// use orx_concurrent_option::*;
440    ///
441    /// fn is_even(n: &i32) -> bool {
442    ///     n % 2 == 0
443    /// }
444    /// unsafe
445    /// {
446    ///     assert_eq!(ConcurrentOption::none().filter(is_even), None);
447    ///     assert_eq!(ConcurrentOption::some(3).filter(is_even), None);
448    ///     assert_eq!(ConcurrentOption::some(4).filter(is_even), Some(&4));
449    /// }
450    /// ```
451    pub unsafe fn filter<P>(&self, predicate: P) -> Option<&T>
452    where
453        P: FnOnce(&T) -> bool,
454    {
455        match self.spin_get_handle(SOME, SOME) {
456            Some(_handle) => {
457                let x = unsafe { MaybeUninit::assume_init_ref(&*self.value.get()) };
458                match predicate(x) {
459                    true => Some(x),
460                    false => None,
461                }
462            }
463            None => None,
464        }
465    }
466}
467
468impl<T> ConcurrentOption<&T> {
469    /// Maps an `ConcurrentOption<&T>` to an `Option<T>` by cloning the contents of the
470    /// option.
471    ///
472    /// # Examples
473    ///
474    /// ```
475    /// use orx_concurrent_option::*;
476    /// use core::sync::atomic::Ordering;
477    ///
478    /// let x = 12;
479    /// let opt_x = ConcurrentOption::some(&x);
480    /// assert_eq!(unsafe { opt_x.as_ref() }, Some(&&12));
481    ///
482    /// let cloned = opt_x.cloned();
483    /// assert_eq!(cloned, Some(12));
484    /// ```
485    pub fn cloned(mut self) -> Option<T>
486    where
487        T: Clone,
488    {
489        self.exclusive_take().cloned()
490    }
491
492    /// Maps an `ConcurrentOption<&T>` to an `Option<T>` by copying the contents of the
493    /// option.
494    ///
495    /// # Examples
496    ///
497    /// ```
498    /// use orx_concurrent_option::*;
499    ///
500    /// let x = 12;
501    /// let opt_x = ConcurrentOption::some(&x);
502    /// assert_eq!(unsafe { opt_x.as_ref() }, Some(&&12));
503    ///
504    /// let copied = opt_x.copied();
505    /// assert_eq!(copied, Some(12));
506    /// ```
507    pub fn copied(mut self) -> Option<T>
508    where
509        T: Copy,
510    {
511        self.exclusive_take().copied()
512    }
513}
514
515impl<T> ConcurrentOption<ConcurrentOption<T>> {
516    /// Converts from `ConcurrentOption<ConcurrentOption<T>>` to `Option<T>`.
517    ///
518    /// # Examples
519    ///
520    /// Basic usage:
521    ///
522    /// ```
523    /// use orx_concurrent_option::*;
524    ///
525    /// let x: ConcurrentOption<ConcurrentOption<u32>> = ConcurrentOption::some(ConcurrentOption::some(6));
526    /// assert_eq!(Some(6), x.flatten());
527    ///
528    /// let x: ConcurrentOption<ConcurrentOption<u32>> = ConcurrentOption::some(ConcurrentOption::none());
529    /// assert_eq!(None, x.flatten());
530    ///
531    /// let x: ConcurrentOption<ConcurrentOption<u32>> = ConcurrentOption::none();
532    /// assert_eq!(None, x.flatten());
533    /// ```
534    pub fn flatten(mut self) -> Option<T> {
535        self.exclusive_take().and_then(|mut x| x.exclusive_take())
536    }
537}
538
539impl<T> ConcurrentOption<Option<T>> {
540    /// Converts from `ConcurrentOption<Option<T>>` to `Option<T>`.
541    ///
542    /// # Examples
543    ///
544    /// Basic usage:
545    ///
546    /// ```
547    /// use orx_concurrent_option::*;
548    ///
549    /// let x: ConcurrentOption<Option<u32>> = ConcurrentOption::some(Some(6));
550    /// assert_eq!(Some(6), x.flatten());
551    ///
552    /// let x: ConcurrentOption<Option<u32>> = ConcurrentOption::some(None);
553    /// assert_eq!(None, x.flatten());
554    ///
555    /// let x: ConcurrentOption<Option<u32>> = ConcurrentOption::none();
556    /// assert_eq!(None, x.flatten());
557    /// ```
558    pub fn flatten(mut self) -> Option<T> {
559        self.exclusive_take().and_then(|x| x)
560    }
561}