Skip to main content

perspective_viewer/utils/
pending_effects.rs

1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ ██████ ██████ ██████       █      █      █      █      █ █▄  ▀███ █       ┃
3// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█  ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄  ▀█ █ ▀▀▀▀▀ ┃
4// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄   █ ▄▄▄▄▄ ┃
5// ┃ █      ██████ █  ▀█▄       █ ██████      █      ███▌▐███ ███████▄ █       ┃
6// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7// ┃ Copyright (c) 2017, the Perspective Authors.                              ┃
8// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9// ┃ This file is part of the Perspective library, distributed under the terms ┃
10// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
13use std::cell::Cell;
14use std::rc::Rc;
15
16use super::pubsub::PubSub;
17
18/// The element-scoped ledger of in-flight EFFECTS: every effectful public
19/// method (and the internal flows they schedule, e.g. the `before-resize`
20/// presize) registers an [`EffectGuard`] for the duration of its async
21/// work, whether or not the caller awaited it. `flush()` resolves only
22/// after the ledger drains, so "called before `flush`" implies "applied
23/// before `flush` resolves".
24#[derive(Clone, Default)]
25pub struct EffectLedger(Rc<EffectLedgerData>);
26
27#[derive(Default)]
28struct EffectLedgerData {
29    count: Cell<u32>,
30    on_drain: PubSub<()>,
31}
32
33pub struct EffectGuard(EffectLedger);
34
35impl EffectLedger {
36    pub fn guard(&self) -> EffectGuard {
37        self.0.count.set(self.0.count.get() + 1);
38        EffectGuard(self.clone())
39    }
40
41    pub fn is_empty(&self) -> bool {
42        self.0.count.get() == 0
43    }
44
45    pub async fn settle(&self) {
46        while self.0.count.get() > 0 {
47            if self.0.on_drain.read_next().await.is_err() {
48                break;
49            }
50        }
51    }
52}
53
54impl Drop for EffectGuard {
55    fn drop(&mut self) {
56        let data = &self.0.0;
57        data.count.set(data.count.get() - 1);
58        if data.count.get() == 0 {
59            data.on_drain.emit(());
60        }
61    }
62}