Skip to main content

incular_core/
key.rs

1//! Widget identity keys.
2//!
3//! Keys are intentionally independent from a particular element tree. A
4//! widget can expose a borrowed [`Key`] while the tree stores a cloneable
5//! [`KeyHandle`] for reconciliation. [`UniqueKey`] values are local keys:
6//! every call to [`UniqueKey::new`] produces a distinct identity, including
7//! when two values have the same type and are otherwise empty.
8
9use std::{
10    any::{Any, TypeId},
11    fmt,
12    hash::{Hash, Hasher},
13    sync::atomic::{AtomicU64, Ordering},
14};
15
16static NEXT_UNIQUE_KEY: AtomicU64 = AtomicU64::new(1);
17
18fn next_unique_key() -> u64 {
19    NEXT_UNIQUE_KEY
20        .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |id| id.checked_add(1))
21        .expect("unique key identity space exhausted")
22}
23
24/// A compact, hashable description of a concrete key.
25#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
26pub struct KeyId {
27    type_id: TypeId,
28    hash: u64,
29}
30
31impl KeyId {
32    #[must_use]
33    pub const fn type_id(self) -> TypeId {
34        self.type_id
35    }
36
37    #[must_use]
38    pub const fn hash(self) -> u64 {
39        self.hash
40    }
41}
42
43/// A type-erased identity used by widgets and reconciliation algorithms.
44/// Implementors should be immutable value types.
45pub trait Key: Any + fmt::Debug {
46    /// Returns a stable, process-local identity for this key value.
47    fn key_id(&self) -> KeyId;
48
49    /// Supports equality after type erasure without requiring `dyn Key` to
50    /// implement `Eq` itself.
51    fn eq_key(&self, other: &dyn Key) -> bool;
52
53    /// Clones a concrete key through a trait object.
54    fn clone_box(&self) -> Box<dyn Key>;
55
56    /// Provides a downcast hook for custom key implementations.
57    fn as_any(&self) -> &dyn Any;
58}
59
60/// Marker for keys whose identity is scoped to a local widget tree.
61pub trait LocalKey: Key {}
62
63/// A globally unique local key. It is useful for forcing a fresh element when
64/// a widget is rebuilt, and is intentionally not based on object addresses.
65#[derive(Clone, Copy, PartialEq, Eq, Hash)]
66pub struct UniqueKey(u64);
67
68impl UniqueKey {
69    #[must_use]
70    pub fn new() -> Self {
71        Self(next_unique_key())
72    }
73
74    #[must_use]
75    pub const fn id(self) -> u64 {
76        self.0
77    }
78}
79
80impl Default for UniqueKey {
81    fn default() -> Self {
82        Self::new()
83    }
84}
85
86impl fmt::Debug for UniqueKey {
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        f.debug_tuple("UniqueKey").field(&self.0).finish()
89    }
90}
91
92impl Key for UniqueKey {
93    fn key_id(&self) -> KeyId {
94        KeyId {
95            type_id: TypeId::of::<Self>(),
96            hash: self.0,
97        }
98    }
99
100    fn eq_key(&self, other: &dyn Key) -> bool {
101        other
102            .as_any()
103            .downcast_ref::<Self>()
104            .is_some_and(|other| self == other)
105    }
106
107    fn clone_box(&self) -> Box<dyn Key> {
108        Box::new(*self)
109    }
110
111    fn as_any(&self) -> &dyn Any {
112        self
113    }
114}
115
116impl LocalKey for UniqueKey {}
117
118/// A value-based local key. `ValueKey<T>` is the Rust equivalent of Flutter's
119/// `ValueKey<T>` while remaining useful for any `Eq + Hash` value.
120#[derive(Clone, Debug, PartialEq, Eq, Hash)]
121pub struct ValueKey<T>(pub T);
122
123impl<T> ValueKey<T> {
124    #[must_use]
125    pub const fn new(value: T) -> Self {
126        Self(value)
127    }
128
129    #[must_use]
130    pub const fn value(&self) -> &T {
131        &self.0
132    }
133}
134
135impl<T> Key for ValueKey<T>
136where
137    T: Any + Clone + Eq + Hash + fmt::Debug,
138{
139    fn key_id(&self) -> KeyId {
140        let mut hasher = std::collections::hash_map::DefaultHasher::new();
141        self.hash(&mut hasher);
142        KeyId {
143            type_id: TypeId::of::<Self>(),
144            hash: hasher.finish(),
145        }
146    }
147
148    fn eq_key(&self, other: &dyn Key) -> bool {
149        other
150            .as_any()
151            .downcast_ref::<Self>()
152            .is_some_and(|other| self == other)
153    }
154
155    fn clone_box(&self) -> Box<dyn Key> {
156        Box::new(self.clone())
157    }
158
159    fn as_any(&self) -> &dyn Any {
160        self
161    }
162}
163
164impl<T> LocalKey for ValueKey<T> where T: Any + Clone + Eq + Hash + fmt::Debug {}
165
166/// Convenient string key constructor.
167pub type StringKey = ValueKey<String>;
168
169/// Compatibility name for value/object keys.
170pub type KeyObject<T> = ValueKey<T>;
171
172/// Cloneable type-erased key. This is the type to use in a heterogeneous key
173/// field or collection.
174pub struct KeyHandle(Box<dyn Key>);
175
176impl KeyHandle {
177    #[must_use]
178    pub fn new<K>(key: K) -> Self
179    where
180        K: Key,
181    {
182        Self(Box::new(key))
183    }
184
185    #[must_use]
186    pub fn as_key(&self) -> &dyn Key {
187        &*self.0
188    }
189
190    #[must_use]
191    pub fn key_id(&self) -> KeyId {
192        self.0.key_id()
193    }
194}
195
196impl Clone for KeyHandle {
197    fn clone(&self) -> Self {
198        Self(self.0.clone_box())
199    }
200}
201
202impl fmt::Debug for KeyHandle {
203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204        f.debug_tuple("KeyHandle").field(&self.0).finish()
205    }
206}
207
208impl PartialEq for KeyHandle {
209    fn eq(&self, other: &Self) -> bool {
210        self.0.eq_key(&*other.0)
211    }
212}
213
214impl Eq for KeyHandle {}
215
216impl Hash for KeyHandle {
217    fn hash<H: Hasher>(&self, state: &mut H) {
218        Hash::hash(&self.key_id(), state);
219    }
220}
221
222impl Key for KeyHandle {
223    fn key_id(&self) -> KeyId {
224        self.0.key_id()
225    }
226
227    fn eq_key(&self, other: &dyn Key) -> bool {
228        other
229            .as_any()
230            .downcast_ref::<Self>()
231            .is_some_and(|other| self == other)
232    }
233
234    fn clone_box(&self) -> Box<dyn Key> {
235        Box::new(self.clone())
236    }
237
238    fn as_any(&self) -> &dyn Any {
239        self
240    }
241}
242
243impl LocalKey for KeyHandle {}
244
245impl From<String> for KeyHandle {
246    fn from(value: String) -> Self {
247        Self::new(StringKey::new(value))
248    }
249}
250
251impl From<&str> for KeyHandle {
252    fn from(value: &str) -> Self {
253        Self::new(StringKey::new(value.to_owned()))
254    }
255}
256
257impl From<UniqueKey> for KeyHandle {
258    fn from(value: UniqueKey) -> Self {
259        Self::new(value)
260    }
261}
262
263impl<T> From<ValueKey<T>> for KeyHandle
264where
265    T: Any + Clone + Eq + Hash + fmt::Debug,
266{
267    fn from(value: ValueKey<T>) -> Self {
268        Self::new(value)
269    }
270}