Skip to main content

ferroui_base/utilities/
synchronous_completion_async_result.rs

1use std::cell::RefCell;
2use std::rc::Rc;
3
4/// The result of an operation that either has completed already or completes
5/// later, in which case its continuations run synchronously at completion.
6#[derive(Clone)]
7pub struct SynchronousCompletionAsyncResult<T: Clone> {
8    state: State<T>,
9}
10
11#[derive(Clone)]
12enum State<T: Clone> {
13    Result(T),
14    Source(SynchronousCompletionAsyncResultSource<T>),
15}
16
17impl<T: Clone + 'static> SynchronousCompletionAsyncResult<T> {
18    /// Creates a completed result.
19    pub fn new(result: T) -> Self {
20        Self { state: State::Result(result) }
21    }
22
23    pub fn is_completed(&self) -> bool {
24        match &self.state {
25            State::Result(_) => true,
26            State::Source(source) => source.is_completed(),
27        }
28    }
29
30    /// The result. Panics if the operation is not yet completed.
31    pub fn get_result(&self) -> T {
32        match &self.state {
33            State::Result(result) => result.clone(),
34            State::Source(source) => source.result(),
35        }
36    }
37
38    /// Runs `continuation` now if the operation has completed without a
39    /// source, otherwise when the source completes.
40    pub fn on_completed(&self, continuation: impl FnOnce() + 'static) {
41        match &self.state {
42            State::Result(_) => continuation(),
43            State::Source(source) => source.on_completed(Box::new(continuation)),
44        }
45    }
46}
47
48struct SourceInner<T> {
49    result: Option<T>,
50    continuations: Vec<Box<dyn FnOnce()>>,
51}
52
53/// The producer side of a [`SynchronousCompletionAsyncResult`].
54pub struct SynchronousCompletionAsyncResultSource<T> {
55    inner: Rc<RefCell<SourceInner<T>>>,
56}
57
58impl<T> Clone for SynchronousCompletionAsyncResultSource<T> {
59    fn clone(&self) -> Self {
60        Self { inner: self.inner.clone() }
61    }
62}
63
64impl<T: Clone + 'static> Default for SynchronousCompletionAsyncResultSource<T> {
65    fn default() -> Self {
66        Self::new()
67    }
68}
69
70impl<T: Clone + 'static> SynchronousCompletionAsyncResultSource<T> {
71    pub fn new() -> Self {
72        Self { inner: Rc::new(RefCell::new(SourceInner { result: None, continuations: Vec::new() })) }
73    }
74
75    /// The consumer side of the operation.
76    pub fn async_result(&self) -> SynchronousCompletionAsyncResult<T> {
77        SynchronousCompletionAsyncResult { state: State::Source(self.clone()) }
78    }
79
80    pub(crate) fn is_completed(&self) -> bool {
81        self.inner.borrow().result.is_some()
82    }
83
84    pub(crate) fn result(&self) -> T {
85        self.inner.borrow().result.clone().expect("Asynchronous operation is not yet completed")
86    }
87
88    pub(crate) fn on_completed(&self, continuation: Box<dyn FnOnce()>) {
89        self.inner.borrow_mut().continuations.push(continuation);
90    }
91
92    /// Completes the operation and runs its continuations. Panics if it is
93    /// already completed.
94    pub fn set_result(&self, result: T) {
95        let continuations = {
96            let mut inner = self.inner.borrow_mut();
97            if inner.result.is_some() {
98                panic!("Asynchronous operation is already completed");
99            }
100            inner.result = Some(result);
101            std::mem::take(&mut inner.continuations)
102        };
103        for continuation in continuations {
104            continuation();
105        }
106    }
107
108    /// Completes the operation unless it is already completed.
109    pub fn try_set_result(&self, result: T) {
110        if self.is_completed() {
111            return;
112        }
113        self.set_result(result);
114    }
115}