rx_rust/disposable/
shared_disposal.rs1use crate::{
2 disposable::Disposable,
3 utils::{
4 id_generator::{Id, IdGenerator},
5 mutable::{Mutable, MutableHelper},
6 types::Shared,
7 },
8};
9use educe::Educe;
10
11#[derive(Educe)]
12#[educe(Debug, Default)]
13enum State<D> {
14 #[educe(Default)]
15 Idle,
16 Building(Id),
20 Active(D),
21 Disposed,
22}
23
24#[derive(Educe)]
25#[educe(Debug, Default)]
26struct Inner<D> {
27 state: State<D>,
28 id_generator: IdGenerator,
29}
30
31#[derive(Educe)]
32#[educe(Debug, Clone, Default)]
33pub struct SharedDisposal<D>(Shared<Mutable<Inner<D>>>);
34
35impl<D> SharedDisposal<D> {
36 pub fn replace(&self, disposal_builder: impl FnOnce() -> D)
37 where
38 D: Disposable,
39 {
40 let (id, superseded) = self.0.with_mut(|inner| {
42 if matches!(inner.state, State::Disposed) {
43 return (None, None);
44 }
45 let id = inner.id_generator.next_id();
46 match std::mem::replace(&mut inner.state, State::Building(id)) {
47 State::Idle | State::Building(_) => (Some(id), None),
48 State::Active(disposal) => (Some(id), Some(disposal)),
49 State::Disposed => unreachable!("the disposed state returned above"),
50 }
51 });
52 if let Some(disposal) = superseded {
53 disposal.dispose();
54 }
55
56 let Some(id) = id else {
57 return;
58 };
59
60 let disposable = disposal_builder();
61
62 let stale = self.0.with_mut(|inner| {
63 let is_current = match &inner.state {
64 State::Building(current) => *current == id,
65 State::Idle | State::Active(_) | State::Disposed => false,
66 };
67 if is_current {
68 inner.state = State::Active(disposable);
69 None
70 } else {
71 Some(disposable)
73 }
74 });
75 if let Some(disposable) = stale {
76 disposable.dispose();
77 }
78 }
79}
80
81impl<D> Disposable for SharedDisposal<D>
82where
83 D: Disposable,
84{
85 fn dispose(self) {
86 match self
89 .0
90 .with_mut(|inner| std::mem::replace(&mut inner.state, State::Disposed))
91 {
92 State::Idle | State::Building(_) | State::Disposed => {}
93 State::Active(disposable) => {
94 Disposable::dispose(disposable);
95 }
96 }
97 }
98}