ribir_core/builtin_widgets/
key.rs1use std::{
2 cmp::{Eq, Ord, PartialOrd},
3 fmt::Debug,
4};
5
6use crate::prelude::*;
7
8#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
11pub enum Key {
12 Kusize(usize),
13 Ku1(u8),
14 Ku2(u16),
15 Ku4(u32),
16 Ku8(u64),
17 Ku16(u128),
18
19 Kisize(isize),
20 Ki1(i8),
21 Ki2(i16),
22 Ki4(i32),
23 Ki8(i64),
24 Ki16(i128),
25
26 Kbool(bool),
27 Kchar(char),
28
29 Kstring(String),
30 K32([u8; 32]),
31}
32
33#[derive(Clone, Debug, PartialEq, Copy)]
34pub struct KeyChange<V>(pub Option<V>, pub V);
35
36impl<V: Default> Default for KeyChange<V> {
37 fn default() -> Self { KeyChange(None, V::default()) }
38}
39
40#[derive(Declare)]
80pub struct KeyWidget<V: 'static> {
81 pub key: Key,
82 #[declare(strict)]
83 pub value: V,
84 #[declare(skip)]
85 before_value: Option<V>,
86 #[declare(skip)]
87 has_successor: bool,
88}
89
90pub(crate) trait AnyKey: Any {
93 fn key(&self) -> Key;
94 fn record_prev_key_widget(&self, key: &dyn AnyKey);
96 fn record_next_key_widget(&self, key: &dyn AnyKey);
98 fn as_any(&self) -> &dyn Any;
99}
100
101impl<T, V> AnyKey for T
102where
103 T: StateWriter<Value = KeyWidget<V>>,
104 V: Clone + PartialEq + 'static,
105{
106 fn key(&self) -> Key { self.read().key.clone() }
107
108 fn record_prev_key_widget(&self, key: &dyn AnyKey) {
109 assert_eq!(self.key(), key.key());
110 let Some(key) = key.as_any().downcast_ref::<Self>() else {
111 log::warn!("Different value type for same key.");
112 return;
113 };
114 self
115 .write()
116 .record_before_value(key.read().value.clone());
117 }
118
119 fn record_next_key_widget(&self, _: &dyn AnyKey) { self.silent().has_successor = true; }
120
121 fn as_any(&self) -> &dyn Any { self }
122}
123
124impl<V: 'static + Default + Clone + PartialEq> ComposeChild for KeyWidget<V> {
125 type Child = Widget;
126 #[inline]
127 fn compose_child(this: impl StateWriter<Value = Self>, child: Self::Child) -> impl WidgetBuilder {
128 fn_widget! {
129 let data: Box<dyn AnyKey> = Box::new(this);
130 child.attach_data(data, ctx!()).build(ctx!())
131 }
132 }
133}
134
135impl Query for Box<dyn AnyKey> {
136 crate::widget::impl_query_self_only!();
137}
138
139impl<V> KeyWidget<V>
140where
141 V: Clone + PartialEq,
142{
143 pub fn is_enter(&self) -> bool { self.before_value.is_none() }
146 pub fn is_leave(&self) -> bool { !self.has_successor }
149
150 pub fn is_changed(&self) -> bool {
152 self.before_value.is_some() && self.before_value.as_ref() != Some(&self.value)
153 }
154
155 pub fn get_change(&self) -> KeyChange<V> {
156 KeyChange(self.before_value.clone(), self.value.clone())
157 }
158
159 pub fn before_value(&self) -> Option<&V> { self.before_value.as_ref() }
160
161 fn record_before_value(&mut self, value: V) { self.before_value = Some(value); }
162}
163
164macro_rules! from_key_impl {
165 ($($ty: ty : $name: ident)*) => {
166 $(
167 impl From<$ty> for Key {
168 fn from(s: $ty) -> Self {
169 Key::$name(s)
170 }
171 }
172 )*
173 };
174}
175
176from_key_impl!(
177 usize:Kusize u8:Ku1 u16:Ku2 u32:Ku4 u64:Ku8 u128:Ku16
178 isize:Kisize i8:Ki1 i16:Ki2 i32:Ki4 i64:Ki8 i128:Ki16
179 bool:Kbool char:Kchar
180 [u8;32]:K32
181);
182
183const MAX_KEY_STR: usize = 16;
184
185impl From<String> for Key {
186 fn from(s: String) -> Self {
187 if s.len() < MAX_KEY_STR {
188 Key::Kstring(s)
189 } else {
190 Key::K32(blake3::hash(s.as_bytes()).into())
191 }
192 }
193}
194
195impl From<&str> for Key {
196 fn from(s: &str) -> Self {
197 if s.len() < MAX_KEY_STR {
198 Key::Kstring(s.to_owned())
199 } else {
200 Key::K32(blake3::hash(s.as_bytes()).into())
201 }
202 }
203}
204
205#[macro_export]
206macro_rules! complex_key {
207 ($($k: expr),*) => {{
208 let mut hasher = blake3::Hasher::new();
209 $(
210 $k.consume(&mut hasher);
211 )*
212 let bytes: [u8;32] = hasher.finalize().into();
213 bytes
214 }};
215}
216pub trait ConsumeByHasher {
217 fn consume(self, hasher: &mut blake3::Hasher);
218}
219
220impl ConsumeByHasher for String {
221 #[inline]
222 fn consume(self, hasher: &mut blake3::Hasher) { hasher.update(self.as_bytes()); }
223}
224
225impl<'a> ConsumeByHasher for &'a str {
226 #[inline]
227 fn consume(self, hasher: &mut blake3::Hasher) { hasher.update(self.as_bytes()); }
228}
229
230macro_rules! impl_as_u8_consume_by_hasher {
231 ($($t: ty)*) => {
232 $(
233 impl ConsumeByHasher for $t {
234 #[inline]
235 fn consume(self, hasher: &mut blake3::Hasher) {
236 hasher.update(&[self as u8]);
237 }
238 }
239 )*
240 };
241}
242impl_as_u8_consume_by_hasher!(bool char);
243
244macro_rules! impl_bytes_consume_by_hasher {
245 ($($ty: ty)*) => {
246 $(
247 impl ConsumeByHasher for $ty {
248 #[inline]
249 fn consume(self, hasher: &mut blake3::Hasher) {
250 hasher.update(&self.to_ne_bytes());
251 }
252 }
253 )*
254 };
255}
256
257impl_bytes_consume_by_hasher!(
258 usize u8 u16 u32 u64 u128
259 isize i8 i16 i32 i64 i128
260 f32 f64
261);
262
263#[test]
264fn key_detect() {
265 let k1: Key = 0i32.into();
266 let k2: Key = String::new().into();
267 let k3: Key = "".into();
268 let ck1 = complex_key!("asd", true, 1);
269 let ck2 = complex_key!("asd", true, 1);
270 assert!(k1 != k2);
271 assert!(k2 == k3);
272 assert!(k3 != k1);
273 assert!(ck1 == ck2);
274}