Skip to main content

orx_concurrent_option/
mut_handle.rs

1use crate::{ConcurrentOption, states::*};
2use core::{
3    cell::UnsafeCell,
4    mem::MaybeUninit,
5    sync::atomic::{AtomicU8, Ordering},
6};
7
8/// Provides a mut-handle on the optional.
9pub struct MutHandle<'a, T> {
10    state: &'a AtomicU8,
11    success_state: StateU8,
12    /// Provides direct access to the cell holding the data of the optional.
13    pub value: &'a UnsafeCell<MaybeUninit<T>>,
14}
15
16impl<'a, T> MutHandle<'a, T> {
17    pub(crate) fn spin_get(
18        option: &'a ConcurrentOption<T>,
19        initial_state: StateU8,
20        success_state: StateU8,
21    ) -> Option<Self> {
22        loop {
23            match option.state.compare_exchange(
24                initial_state,
25                RESERVED,
26                Ordering::Acquire,
27                Ordering::Relaxed,
28            ) {
29                Ok(_) => {
30                    return Some(Self {
31                        state: &option.state,
32                        success_state,
33                        value: &option.value,
34                    });
35                }
36                Err(previous_state) => match previous_state {
37                    RESERVED => continue,
38                    _ => return None,
39                },
40            }
41        }
42    }
43
44    /// Creates a `&mut T` reference to the underlying value of the optional.
45    ///
46    /// # Safety
47    ///
48    /// This operation might lead to undefined behavior:
49    /// * if we use it while other threads are accessing the data, or
50    /// * if the optional `is_none` when we access the value.
51    #[allow(clippy::mut_from_ref)]
52    pub unsafe fn get_mut(&self) -> &mut T {
53        let x = unsafe { &mut *self.value.get() };
54        unsafe { MaybeUninit::assume_init_mut(x) }
55    }
56}
57
58impl<T> Drop for MutHandle<'_, T> {
59    fn drop(&mut self) {
60        self.state
61            .compare_exchange(
62                RESERVED,
63                self.success_state,
64                Ordering::Release,
65                Ordering::Relaxed,
66            )
67            .expect("Failed to update the concurrent state after concurrent state mutation");
68    }
69}