Skip to main content

orx_concurrent_option/
exclusive.rs

1use crate::{ConcurrentOption, states::*};
2use core::{
3    mem::MaybeUninit,
4    ops::{Deref, DerefMut},
5    sync::atomic::Ordering,
6};
7
8impl<T> ConcurrentOption<T> {
9    /// Converts from `Option<T>` (or `&mut Option<T>`) to `Option<&mut T::Target>`.
10    ///
11    /// Leaves the original `Option` in-place, creating a new one containing a mutable reference to
12    /// the inner type's [`Deref::Target`] type.
13    ///
14    /// # Examples
15    ///
16    /// ```rust
17    /// use orx_concurrent_option::*;
18    ///
19    /// let mut x: ConcurrentOption<String> = ConcurrentOption::some("hey".to_owned());
20    /// assert_eq!(x.exclusive_as_deref_mut().map(|x| {
21    ///     x.make_ascii_uppercase();
22    ///     x
23    /// }), Some("HEY".to_owned().as_mut_str()));
24    /// ```
25    pub fn exclusive_as_deref_mut(&mut self) -> Option<&mut <T as Deref>::Target>
26    where
27        T: DerefMut,
28    {
29        self.exclusive_as_mut().map(|x| x.deref_mut())
30    }
31
32    /// Converts from `&mut Option<T>` to `Option<&mut T>`.
33    ///
34    /// # Examples
35    ///
36    /// ```rust
37    /// use orx_concurrent_option::*;
38    ///
39    /// let mut x = ConcurrentOption::some(2);
40    /// match x.exclusive_as_mut() {
41    ///     Some(v) => *v = 42,
42    ///     None => {},
43    /// }
44    /// assert_eq!(unsafe { x.as_ref() }, Some(&42));
45    /// ```
46    pub fn exclusive_as_mut(&mut self) -> Option<&mut T> {
47        match self.state.load(Ordering::Relaxed) {
48            SOME => Some(unsafe { (*self.value.get()).assume_init_mut() }),
49            _ => None,
50        }
51    }
52
53    /// Takes the value out of the option, leaving a None in its place.
54    ///
55    /// # Examples
56    ///
57    /// ```rust
58    /// use orx_concurrent_option::*;
59    ///
60    /// let mut x = ConcurrentOption::some(42);
61    /// let y = x.exclusive_take();
62    /// assert_eq!(x, ConcurrentOption::none());
63    /// assert_eq!(y, Some(42));
64    ///
65    /// let mut x: ConcurrentOption<u32> = ConcurrentOption::none();
66    /// let y = x.exclusive_take();
67    /// assert_eq!(x, ConcurrentOption::none());
68    /// assert_eq!(y, None);
69    /// ```
70    pub fn exclusive_take(&mut self) -> Option<T> {
71        match self.state.load(Ordering::Relaxed) {
72            SOME => {
73                self.state.store(NONE, Ordering::Relaxed);
74                let x = unsafe { &mut *self.value.get() };
75                Some(unsafe { x.assume_init_read() })
76            }
77            _ => None,
78        }
79    }
80
81    /// Takes the value out of the option, but only if the predicate evaluates to
82    /// `true` on a mutable reference to the value.
83    ///
84    /// In other words, replaces `self` with None if the predicate returns `true`.
85    /// This method operates similar to [`ConcurrentOption::exclusive_take`] but conditional.
86    ///
87    /// # Examples
88    ///
89    /// ```rust
90    /// use orx_concurrent_option::*;
91    ///
92    /// let mut x = ConcurrentOption::some(42);
93    ///
94    /// let prev = x.exclusive_take_if(|v| if *v == 42 {
95    ///     *v += 1;
96    ///     false
97    /// } else {
98    ///     false
99    /// });
100    /// assert_eq!(x, ConcurrentOption::some(43));
101    /// assert_eq!(prev, None);
102    ///
103    /// let prev = x.exclusive_take_if(|v| *v == 43);
104    /// assert_eq!(x, ConcurrentOption::none());
105    /// assert_eq!(prev, Some(43));
106    /// ```
107    pub fn exclusive_take_if<P>(&mut self, predicate: P) -> Option<T>
108    where
109        P: FnOnce(&mut T) -> bool,
110    {
111        match self.exclusive_as_mut().is_some_and(predicate) {
112            true => self.exclusive_take(),
113            false => None,
114        }
115    }
116
117    /// Returns a mutable iterator over the possibly contained value; yields
118    /// * the single element if the option is of Some variant;
119    /// * no elements otherwise.
120    ///
121    /// # Examples
122    ///
123    /// ```rust
124    /// use orx_concurrent_option::*;
125    ///
126    /// let mut x = ConcurrentOption::some(4);
127    /// match x.exclusive_iter_mut().next() {
128    ///     Some(v) => *v = 42,
129    ///     None => {},
130    /// }
131    /// assert_eq!(x, ConcurrentOption::some(42));
132    ///
133    /// let mut x: ConcurrentOption<u32> = ConcurrentOption::none();
134    /// assert_eq!(x.exclusive_iter_mut().next(), None);
135    /// ```
136    pub fn exclusive_iter_mut(&mut self) -> crate::iter::IterMut<'_, T> {
137        let maybe = self.exclusive_as_mut();
138        crate::iter::IterMut { maybe }
139    }
140
141    /// Replaces the actual value in the option by the value given in parameter,
142    /// returning the old value if present,
143    /// leaving a Some in its place without de-initializing either one.
144    ///
145    /// # Examples
146    ///
147    /// ```rust
148    /// use orx_concurrent_option::*;
149    ///
150    /// let mut x = ConcurrentOption::some(2);
151    /// let old = x.exclusive_replace(5);
152    /// assert_eq!(x, ConcurrentOption::some(5));
153    /// assert_eq!(old, Some(2));
154    ///
155    /// let mut x: ConcurrentOption<u32> = ConcurrentOption::none();
156    /// let old = x.exclusive_replace(3);
157    /// assert_eq!(x, ConcurrentOption::some(3));
158    /// assert_eq!(old, None);
159    /// ```
160    #[allow(clippy::panic, clippy::missing_panics_doc)]
161    pub fn exclusive_replace(&mut self, value: T) -> Option<T> {
162        match self.state.load(Ordering::Relaxed) {
163            SOME => {
164                self.state.store(RESERVED, Ordering::Relaxed);
165                let x = unsafe { (*self.value.get()).assume_init_mut() };
166                let old = core::mem::replace(x, value);
167                self.state.store(SOME, Ordering::Relaxed);
168                Some(old)
169            }
170            NONE => {
171                self.state.store(RESERVED, Ordering::Relaxed);
172                self.value = MaybeUninit::new(value).into();
173                self.state.store(SOME, Ordering::Relaxed);
174                None
175            }
176            _ => panic!("ConcurrentOption value is `replace`d while its value is being written."),
177        }
178    }
179
180    /// Inserts `value` into the option, then returns a mutable reference to it.
181    ///
182    /// If the option already contains a value, the old value is dropped.
183    ///
184    /// See also [`Option::get_or_insert`], which doesn't update the value if
185    /// the option already contains Some.
186    ///
187    /// # Examples
188    ///
189    /// ```rust
190    /// use orx_concurrent_option::*;
191    ///
192    /// let mut opt: ConcurrentOption<_> = ConcurrentOption::none();
193    ///
194    /// let val = opt.exclusive_insert(1);
195    /// assert_eq!(*val, 1);
196    /// assert_eq!(unsafe { opt.as_ref() }, Some(&1));
197    ///
198    /// let val = opt.exclusive_insert(2);
199    /// assert_eq!(*val, 2);
200    /// *val = 3;
201    /// assert_eq!(opt.unwrap(), 3);
202    /// ```
203    #[allow(clippy::panic, clippy::missing_panics_doc)]
204    pub fn exclusive_insert(&mut self, value: T) -> &mut T {
205        match self.state.load(Ordering::Relaxed) {
206            SOME => {
207                self.state.store(RESERVED, Ordering::Relaxed);
208                let x = unsafe { (*self.value.get()).assume_init_mut() };
209                let _ = core::mem::replace(x, value);
210                self.state.store(SOME, Ordering::Relaxed);
211            }
212            NONE => {
213                self.state.store(RESERVED, Ordering::Relaxed);
214                self.value = MaybeUninit::new(value).into();
215                self.state.store(SOME, Ordering::Relaxed);
216            }
217            _ => panic!("ConcurrentOption value is `insert`ed while its value is being written."),
218        }
219
220        self.exclusive_as_mut().expect("should be some")
221    }
222
223    /// Inserts `value` into the option if it is None, then
224    /// returns a mutable reference to the contained value.
225    ///
226    /// See also [`ConcurrentOption::insert`], which updates the value even if
227    /// the option already contains Some.
228    ///
229    /// # Examples
230    ///
231    /// ```rust
232    /// use orx_concurrent_option::*;
233    ///
234    /// let mut x = ConcurrentOption::none();
235    ///
236    /// {
237    ///     let y: &mut u32 = x.exclusive_get_or_insert(5);
238    ///     assert_eq!(y, &5);
239    ///
240    ///     *y = 7;
241    /// }
242    ///
243    /// assert_eq!(x, ConcurrentOption::some(7));
244    /// ```
245    pub fn exclusive_get_or_insert(&mut self, value: T) -> &mut T {
246        self.exclusive_get_or_insert_with(|| value)
247    }
248
249    /// Inserts a value computed from `f` into the option if it is None,
250    /// then returns a mutable reference to the contained value.
251    ///
252    /// # Examples
253    ///
254    /// ```rust
255    /// use orx_concurrent_option::*;
256    ///
257    /// let mut x = ConcurrentOption::none();
258    ///
259    /// {
260    ///     let y: &mut u32 = x.exclusive_get_or_insert_with(|| 5);
261    ///     assert_eq!(y, &5);
262    ///
263    ///     *y = 7;
264    /// }
265    ///
266    /// assert_eq!(x, ConcurrentOption::some(7));
267    /// ```
268    #[allow(clippy::panic, clippy::missing_panics_doc)]
269    pub fn exclusive_get_or_insert_with<F>(&mut self, f: F) -> &mut T
270    where
271        F: FnOnce() -> T,
272    {
273        match self.state.load(Ordering::Relaxed) {
274            SOME => self.exclusive_as_mut().expect("is guaranteed to be some"),
275            NONE => {
276                self.state.store(RESERVED, Ordering::Relaxed);
277                self.value = MaybeUninit::new(f()).into();
278                self.state.store(SOME, Ordering::Relaxed);
279                self.exclusive_as_mut().expect("is guaranteed to be some")
280            }
281            _ => panic!(
282                "ConcurrentOption `get_or_insert_with` is called while its value is being written."
283            ),
284        }
285    }
286}