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}