1use core::num::NonZeroI32;
16use core::num::TryFromIntError;
17use core::{hash::Hash, ops::Deref};
18
19use crate::{AnyView, View};
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
23pub struct Id(pub(crate) NonZeroI32);
24
25impl From<Id> for i32 {
26 fn from(val: Id) -> Self {
27 val.0.get()
28 }
29}
30
31impl From<NonZeroI32> for Id {
32 fn from(value: NonZeroI32) -> Self {
33 Self(value)
34 }
35}
36
37impl TryFrom<i32> for Id {
38 type Error = TryFromIntError;
39
40 fn try_from(value: i32) -> Result<Self, Self::Error> {
41 NonZeroI32::try_from(value).map(Id)
42 }
43}
44
45#[diagnostic::on_unimplemented(
50 message = "`{Self}` has no stable WaterUI identity",
51 label = "expected a type implementing `Identifiable`",
52 note = "Collections such as `ForEach` and `List` diff items by id, so each item needs `Identifiable`: derive it with `#[derive(Identifiable)]` and `#[id]` on the identifier field (`use waterui::Identifiable;` — the derive is not in the prelude), for a type you do not own, wrap the value with `.use_id(..)` / `.self_id()`."
53)]
54pub trait Identifiable {
55 type Id: Hash + Ord + Clone;
57
58 fn id(&self) -> Self::Id;
60}
61
62#[derive(Debug)]
67pub struct UseId<T, F> {
68 value: T,
70 f: F,
72}
73
74impl<T, F> UseId<T, F> {
75 pub const fn new(value: T, f: F) -> Self {
77 Self { value, f }
78 }
79
80 pub fn into_inner(self) -> T {
82 self.value
83 }
84}
85
86impl<T, F> Deref for UseId<T, F> {
87 type Target = T;
88
89 fn deref(&self) -> &Self::Target {
90 &self.value
91 }
92}
93
94impl<T, F, Id> Identifiable for UseId<T, F>
95where
96 F: Fn(&T) -> Id,
97 Id: Ord + Hash + Clone,
98{
99 type Id = Id;
100
101 fn id(&self) -> Self::Id {
103 (self.f)(&self.value)
104 }
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
111pub struct SelfId<T>(T);
112
113impl<T> SelfId<T> {
114 pub const fn new(value: T) -> Self {
116 Self(value)
117 }
118 pub fn into_inner(self) -> T {
120 self.0
121 }
122}
123
124impl<T: Hash + Ord + Clone> Identifiable for SelfId<T> {
125 type Id = T;
126
127 fn id(&self) -> Self::Id {
129 self.0.clone()
130 }
131}
132
133impl<T> Deref for SelfId<T> {
134 type Target = T;
135
136 fn deref(&self) -> &Self::Target {
137 &self.0
138 }
139}
140
141pub trait IdentifiableExt: Sized {
143 fn use_id<F, Id>(self, f: F) -> UseId<Self, F>
145 where
146 F: Fn(&Self) -> Id,
147 Id: Ord + Hash,
148 {
149 UseId { value: self, f }
150 }
151
152 fn self_id(self) -> SelfId<Self> {
154 SelfId(self)
155 }
156}
157
158impl<T> IdentifiableExt for T {}
159
160#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
164pub struct TaggedView<T, V> {
165 pub tag: T,
167 pub content: V,
169}
170
171impl<T, V: View> TaggedView<T, V> {
172 pub const fn new(tag: T, content: V) -> Self {
174 Self { tag, content }
175 }
176
177 pub fn map<F, T2>(self, f: F) -> TaggedView<T2, V>
179 where
180 F: Fn(T) -> T2,
181 {
182 TaggedView {
183 tag: f(self.tag),
184 content: self.content,
185 }
186 }
187
188 pub fn mapping(self, mapping: &Mapping<T>) -> TaggedView<Id, V>
190 where
191 T: Ord + Clone,
192 {
193 self.map(move |v| mapping.register(v))
194 }
195
196 pub fn erase(self) -> TaggedView<T, AnyView> {
200 TaggedView {
201 tag: self.tag,
202 content: AnyView::new(self.content),
203 }
204 }
205}
206
207use core::cell::RefCell;
208
209use alloc::{collections::btree_map::BTreeMap, rc::Rc};
210use nami::Binding;
211
212#[derive(Debug)]
216struct MappingInner<T> {
217 counter: i32,
219 to_id: BTreeMap<T, Id>,
221 from_id: BTreeMap<Id, T>,
223}
224
225impl<T: Ord + Clone> MappingInner<T> {
226 pub const fn new() -> Self {
228 Self {
229 counter: 1,
230 to_id: BTreeMap::new(),
231 from_id: BTreeMap::new(),
232 }
233 }
234
235 pub fn register(&mut self, value: T) -> Id {
237 let id = Id(NonZeroI32::new(self.counter).expect("counter should not be zero"));
238 self.to_id.insert(value.clone(), id);
239 self.from_id.insert(id, value);
240 self.counter = self
241 .counter
242 .checked_add(1)
243 .expect("counter should not overflow");
244 id
245 }
246
247 pub fn try_to_id(&self, value: &T) -> Option<Id> {
249 self.to_id.get(value).copied()
250 }
251
252 pub fn to_data(&self, id: Id) -> Option<T> {
254 self.from_id.get(&id).cloned()
255 }
256
257 #[allow(clippy::wrong_self_convention)]
259 pub fn to_id(&mut self, value: T) -> Id {
260 self.try_to_id(&value)
261 .unwrap_or_else(|| self.register(value))
262 }
263}
264
265#[derive(Debug)]
270pub struct Mapping<T>(Rc<RefCell<MappingInner<T>>>);
271
272impl<T> Clone for Mapping<T> {
273 fn clone(&self) -> Self {
275 Self(self.0.clone())
276 }
277}
278
279impl<T: Ord + Clone> Default for Mapping<T> {
280 fn default() -> Self {
282 Self::new()
283 }
284}
285
286impl<T: Ord + Clone> Mapping<T> {
287 #[must_use]
289 pub fn new() -> Self {
290 Self(Rc::new(RefCell::new(MappingInner::new())))
291 }
292
293 pub fn register(&self, value: T) -> Id {
295 self.0.borrow_mut().register(value)
296 }
297
298 pub fn try_to_id(&self, value: &T) -> Option<Id> {
300 self.0.borrow().try_to_id(value)
301 }
302
303 pub fn to_id(&self, value: T) -> Id {
305 self.0.borrow_mut().to_id(value)
306 }
307
308 #[must_use]
310 pub fn to_data(&self, id: Id) -> Option<T> {
311 self.0.borrow().to_data(id)
312 }
313
314 #[must_use]
323 pub fn binding(&self, source: &Binding<T>) -> Binding<Id>
324 where
325 T: 'static,
326 {
327 let mapping = self.clone();
328 let mapping2 = self.clone();
329 Binding::mapping(
330 source,
331 move |value| mapping.to_id(value),
332 move |binding, value| {
333 binding.set(
334 mapping2
335 .to_data(value)
336 .expect("Invalid binding mapping : Data not found"),
337 );
338 },
339 )
340 }
341
342 #[must_use]
351 pub fn optional_binding(&self, source: &Binding<Option<T>>) -> Binding<Option<Id>>
352 where
353 T: 'static,
354 {
355 let mapping = self.clone();
356 let mapping2 = self.clone();
357 Binding::mapping(
358 source,
359 move |value| value.map(|value| mapping.to_id(value)),
360 move |binding, value| {
361 binding.set(value.map(|value| {
362 mapping2
363 .to_data(value)
364 .expect("Invalid optional binding mapping : Data not found")
365 }));
366 },
367 )
368 }
369}