rusturnate/
lib.rs

1use core::{
2    cell::UnsafeCell,
3    fmt,
4    marker::PhantomData,
5    panic::{RefUnwindSafe, UnwindSafe},
6    sync::atomic::AtomicPtr,
7};
8#[cfg(feature = "anytime_poisoning")]
9use core::sync::atomic::{AtomicBool, Ordering::Release};
10
11pub use access::*;
12pub use awaiter::await_result;
13use error::IgnorePoison;
14use queue::awaiter;
15use queue::Callback;
16pub use queue::editor;
17use queue::state;
18
19type NotSendOrSync = PhantomData<*const ()>;
20
21pub struct Rusturn<T> {
22    queue: AtomicPtr<Callback>,
23    value: UnsafeCell<Option<T>>,
24
25    #[cfg(feature = "anytime_poisoning")]
26    poisoned: AtomicBool,
27}
28
29unsafe impl<T: Send> Sync for Rusturn<T> {}
30unsafe impl<T: Send> Send for Rusturn<T> {}
31
32impl<T> RefUnwindSafe for Rusturn<T> {}
33impl<T> UnwindSafe for Rusturn<T> {}
34
35impl<T> Default for Rusturn<T> {
36    #[inline]
37    fn default() -> Self {
38        Self::new()
39    }
40}
41
42impl<T> From<T> for Rusturn<T> {
43    #[inline]
44    fn from(value: T) -> Self {
45        Self::with_value(value)
46    }
47}
48
49impl<T> Rusturn<T> {
50    #[must_use]
51    #[inline]
52    pub const fn new() -> Self {
53        Self {
54            queue: AtomicPtr::new(state::NONE_PTR),
55            value: UnsafeCell::new(None),
56
57            #[cfg(feature = "anytime_poisoning")]
58            poisoned: AtomicBool::new(false),
59        }
60    }
61
62    #[must_use]
63    #[inline]
64    pub const fn with_value(value: T) -> Self {
65        Self {
66            queue: AtomicPtr::new(state::DONE_PTR),
67            value: UnsafeCell::new(Some(value)),
68
69            #[cfg(feature = "anytime_poisoning")]
70            poisoned: AtomicBool::new(false),
71        }
72    }
73
74    /// # Safety
75    /// Tell other tasks that a panic occurred
76    /// on your end. They will be woken in a
77    /// poisoned state.
78    /// In particular, this means that the
79    /// currently active or most recently
80    /// finished [`editor::Editor`] (at the
81    /// time of calling this method) encountered
82    /// a panic.
83    /// This call won't block execution.
84    /// You may use this when auto-poisoning
85    /// cannot occur due to `std` not being
86    /// available.
87    #[cfg(feature = "anytime_poisoning")]
88    #[inline]
89    pub unsafe fn mark_poisoned(&self) {
90        // `poisoned` flag will be received in `Editor::try_edit()`
91        self.poisoned.store(true, Release);
92        // Try to wake pending tasks directly. In case of `WouldBlock`,
93        // there is an active `Editor`, which, when dropped, will wake
94        // all pending tasks. `nothing()` drops the poisoned editor
95        // without changing it.
96        match self.try_edit().ignore_poison() {
97            Ok(editor) => editor.action().nothing(),
98            Err(error::InstantAccessError::WouldBlock) => {}
99        }
100    }
101
102    #[inline]
103    pub fn try_edit(&self) -> error::TryEditorAccessResult<'_, T, error::InstantAccessError> {
104        editor::Editor::try_edit(self)
105    }
106}
107
108impl<T> Rusturn<T> {
109    #[must_use]
110    #[inline(always)]
111    pub const fn instant_access(&self) -> Access<&Self, Instantly> {
112        Access::create(self)
113    }
114
115    #[must_use]
116    #[inline(always)]
117    pub const fn blocking_access(&self) -> Access<&Self, Blocking> {
118        Access::create(self)
119    }
120
121    #[must_use]
122    #[inline(always)]
123    pub const fn suspending_access(&self) -> Access<&Self, Suspending> {
124        Access::create(self)
125    }
126}
127
128impl<T: fmt::Debug> fmt::Debug for Rusturn<T> {
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        let mut d = f.debug_struct("Rusturn");
131        let _ = match self.try_edit().ignore_poison() {
132            Ok(editor) => d.field("value", &editor),
133            Err(error::InstantAccessError::WouldBlock) => d.field("value", &format_args!("<busy>")),
134        };
135        d.finish_non_exhaustive()
136    }
137}
138
139mod access;
140pub mod error;
141mod queue;