Skip to main content

gpui_ce_motion/
presence.rs

1//! Keyed mount ownership; callers keep each child's animation state alongside its key.
2use crate::AnimationError;
3
4/// How new keys enter while removed children finish exiting.
5#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
6pub enum PresenceMode {
7    /// Enter new children immediately while removed children exit.
8    #[default]
9    Sync,
10    /// Wait for every removed child to exit before mounting new keys.
11    Wait,
12}
13
14/// A retained key and its requested presence. Exiting keys stay mounted.
15#[derive(Clone, Debug)]
16pub struct PresenceChild<K> {
17    key: K,
18    present: bool,
19}
20
21impl<K> PresenceChild<K> {
22    /// Stable identity used to retrieve the caller's retained child state.
23    pub fn key(&self) -> &K {
24        &self.key
25    }
26
27    /// Feed this into `Motion::present` for the keyed child.
28    pub fn is_present(&self) -> bool {
29        self.present
30    }
31}
32
33/// Keyed enter/exit coordination. Allocates only on membership changes, never on sampling.
34/// Call `finish_exit` after a child's `Frame::is_mounted` becomes false.
35#[derive(Debug)]
36pub struct PresenceGroup<K> {
37    children: Vec<PresenceChild<K>>,
38    pending: Vec<K>,
39    mode: PresenceMode,
40}
41
42impl<K: Clone + PartialEq> PresenceGroup<K> {
43    /// Creates an empty group with explicit overlap/wait behavior.
44    pub fn new(mode: PresenceMode) -> Self {
45        Self {
46            children: Vec::new(),
47            pending: Vec::new(),
48            mode,
49        }
50    }
51
52    /// Reconciles desired keys, rejecting duplicate keys without changing the group.
53    /// Reintroducing an exiting key cancels its removal and preserves its identity.
54    pub fn update(&mut self, keys: impl IntoIterator<Item = K>) -> Result<(), AnimationError> {
55        let keys: Vec<_> = keys.into_iter().collect();
56
57        if keys.iter().enumerate().any(|(i, k)| keys[..i].contains(k)) {
58            return Err(AnimationError::Index);
59        }
60
61        for child in &mut self.children {
62            child.present = keys.contains(&child.key);
63        }
64
65        let waiting = self.mode == PresenceMode::Wait && self.children.iter().any(|c| !c.present);
66
67        self.pending.clear();
68
69        for key in keys {
70            if self.children.iter().any(|c| c.key == key) {
71                continue;
72            }
73
74            if waiting {
75                self.pending.push(key);
76            } else {
77                self.children.push(PresenceChild { key, present: true });
78            }
79        }
80
81        Ok(())
82    }
83
84    /// Mounted children, including exits; keys retain their original mount order.
85    pub fn children(&self) -> &[PresenceChild<K>] {
86        &self.children
87    }
88
89    /// Unmounts an absent key after its exit. Returns false for unknown or present keys.
90    /// The last exit in wait mode mounts the currently requested pending keys.
91    pub fn finish_exit(&mut self, key: &K) -> bool {
92        let Some(ix) = self
93            .children
94            .iter()
95            .position(|c| &c.key == key && !c.present)
96        else {
97            return false;
98        };
99
100        self.children.remove(ix);
101
102        if self.children.iter().all(|c| c.present) {
103            self.children.extend(
104                self.pending
105                    .drain(..)
106                    .map(|key| PresenceChild { key, present: true }),
107            );
108        }
109
110        true
111    }
112}