kas_core/core/
widget_id.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6//! Widget identifiers
7
8// x << a + b is x << (a + b)
9#![allow(clippy::precedence)]
10
11use crate::cast::{Cast, Conv};
12use hash_hasher::{HashBuildHasher, HashedMap};
13use std::cell::RefCell;
14use std::cmp::Ordering;
15use std::collections::hash_map::Entry;
16use std::hash::{DefaultHasher, Hash, Hasher};
17use std::iter::once;
18use std::marker::PhantomData;
19use std::mem::size_of;
20use std::num::NonZeroU64;
21use std::rc::Rc;
22use std::{fmt, slice};
23
24thread_local! {
25    // Map from hash of path to allocated path
26    static DB: RefCell<HashedMap<u64, *mut usize>> = const { RefCell::new(HashedMap::with_hasher(HashBuildHasher::new())) };
27}
28
29/// Invalid (default) identifier
30const INVALID: u64 = !0;
31
32/// Mark for use; one of the below should be set (or both if INVALID)
33const USE_MASK: u64 = 0x3;
34/// `x & USE_MASK == USE_BITS`: rest is a sequence of 4-bit blocks; len is number of blocks used
35const USE_BITS: u64 = 0x01;
36/// `x & USE_MASK == USE_PTR`: high 62 bits are a pointer (or hash: see to_nzu64)
37const USE_PTR: u64 = 0x02;
38
39const MASK_LEN: u64 = 0xF0;
40const SHIFT_LEN: u8 = 4;
41const BLOCKS: u8 = 14;
42const MASK_BITS: u64 = 0xFFFF_FFFF_FFFF_FF00;
43
44const MASK_PTR: u64 = 0xFFFF_FFFF_FFFF_FFFC;
45
46const LEN_MASK: usize = 0xF_FFFF;
47const LEN_INCR: usize = LEN_MASK + 1;
48
49/// Integer or pointer to a reference-counted slice.
50///
51/// Use `Self::get_ptr` to determine the variant used. When reading a pointer,
52/// mask with MASK_PTR.
53///
54/// `self.0 & USE_MASK` are the "flag bits" determining the variant used. This
55/// overlaps with the pointer's lowest bit (which must be zero due to alignment).
56///
57/// `PhantomData<Rc<()>>` is used to impl !Send and !Sync. We need atomic
58/// reference counting to support those.
59struct IntOrPtr(NonZeroU64, PhantomData<Rc<()>>);
60
61#[derive(Clone, Debug, PartialEq, Eq)]
62enum Variant<'a> {
63    Invalid,
64    Int(u64),
65    Slice(&'a [usize]),
66}
67
68fn hash(path: &[usize]) -> u64 {
69    let mut hasher = DefaultHasher::new();
70    path.hash(&mut hasher);
71    hasher.finish()
72}
73
74impl IntOrPtr {
75    const ROOT: Self = IntOrPtr(NonZeroU64::new(USE_BITS).unwrap(), PhantomData);
76    const INVALID: Self = IntOrPtr(NonZeroU64::new(INVALID).unwrap(), PhantomData);
77
78    #[inline]
79    fn get_ptr(&self) -> Option<*mut usize> {
80        if self.0.get() & USE_MASK == USE_PTR {
81            let p = usize::conv(self.0.get() & MASK_PTR);
82            Some(p as *mut usize)
83        } else {
84            None
85        }
86    }
87
88    fn get_slice(&self) -> Option<&[usize]> {
89        self.get_ptr().map(|p| unsafe {
90            let len = *p.offset(1) & LEN_MASK;
91            let p = p.offset(2);
92            slice::from_raw_parts(p, len)
93        })
94    }
95
96    /// Construct from an integer
97    ///
98    /// Note: requires `x & USE_MASK == USE_BITS`.
99    fn new_int(x: u64) -> Self {
100        assert!(x & USE_MASK == USE_BITS);
101        let x = NonZeroU64::new(x).unwrap();
102        let u = IntOrPtr(x, PhantomData);
103        assert!(u.get_ptr().is_none());
104        u
105    }
106
107    /// Construct as a slice from an iterator
108    fn new_iter<I: Clone + Iterator<Item = usize>>(iter: I) -> Self {
109        let ref_count = 1;
110        let len = iter.clone().count();
111        let mut v: Vec<usize> = once(ref_count).chain(once(len)).chain(iter).collect();
112
113        let mut p: Option<*mut usize> = None;
114        let pp = &mut p;
115        DB.with_borrow_mut(move |db| {
116            loop {
117                let x = hash(&v);
118                match db.entry(x) {
119                    Entry::Occupied(entry) => {
120                        let p = *entry.get();
121                        let slice = unsafe { slice::from_raw_parts(p.offset(2), *p.offset(1)) };
122                        if slice == &v[2..] {
123                            unsafe { increment_rc(p) };
124                            *pp = Some(p);
125                            break;
126                        } else {
127                            // Hash collision: tweak the representation and retry
128                            v[1] = v[1].wrapping_add(LEN_INCR);
129                        }
130                    }
131                    Entry::Vacant(entry) => {
132                        let p = Box::leak(v.into_boxed_slice()) as *mut [usize] as *mut usize;
133                        *pp = Some(p);
134                        entry.insert(p);
135                        break;
136                    }
137                }
138            }
139        });
140
141        let p: u64 = (p.expect("failed to access Id DB") as usize).cast();
142        debug_assert_eq!(p & 3, 0);
143        let p = p | USE_PTR;
144        let u = IntOrPtr(NonZeroU64::new(p).unwrap(), PhantomData);
145        assert!(u.get_ptr().is_some());
146        u
147    }
148
149    fn get(&self) -> Variant<'_> {
150        if let Some(slice) = self.get_slice() {
151            Variant::Slice(slice)
152        } else if self.0.get() == INVALID {
153            Variant::Invalid
154        } else {
155            Variant::Int(self.0.get())
156        }
157    }
158
159    fn to_nzu64(&self) -> NonZeroU64 {
160        if let Some(slice) = self.get_slice() {
161            let x = hash(slice) & MASK_PTR;
162            NonZeroU64::new(x | USE_PTR).unwrap()
163        } else {
164            self.0
165        }
166    }
167
168    fn try_from_u64(n: u64) -> Option<IntOrPtr> {
169        match n & USE_MASK {
170            USE_BITS => {
171                // TODO: sanity checks
172                Some(IntOrPtr(NonZeroU64::new(n).unwrap(), PhantomData))
173            }
174            USE_PTR => {
175                let mut result = None;
176                let r = &mut result;
177                DB.with_borrow(|db| {
178                    if let Some(p) = db.get(&n) {
179                        unsafe { increment_rc(*p) };
180                        let p: u64 = (*p as usize).cast();
181                        *r = Some(IntOrPtr(NonZeroU64::new(p).unwrap(), PhantomData))
182                    }
183                });
184                result
185            }
186            _ if n == !0 => Some(IntOrPtr::INVALID),
187            _ => None,
188        }
189    }
190}
191
192/// Increment a IntOrPtr pointer ref-count
193///
194/// Safety: the input must be a valid IntOrPtr pointer value.
195unsafe fn increment_rc(p: *mut usize) {
196    unsafe {
197        let ref_count = *p;
198
199        // Copy behaviour of Rc::clone:
200        if ref_count == 0 || ref_count == usize::MAX {
201            std::process::abort();
202        }
203
204        *p = ref_count + 1;
205    }
206}
207
208impl Clone for IntOrPtr {
209    fn clone(&self) -> Self {
210        if let Some(p) = self.get_ptr() {
211            unsafe { increment_rc(p) };
212        }
213        IntOrPtr(self.0, PhantomData)
214    }
215}
216
217impl Drop for IntOrPtr {
218    fn drop(&mut self) {
219        if let Some(p) = self.get_ptr() {
220            unsafe {
221                let ref_count = *p;
222                if ref_count > 1 {
223                    *p = ref_count - 1;
224                } else {
225                    // len+2 because path len does not include ref_count or len "fields"
226                    let len = (*p.offset(1) & LEN_MASK) + 2;
227                    let slice = slice::from_raw_parts_mut(p, len);
228
229                    let x = hash(slice);
230                    DB.with_borrow_mut(|db| db.remove(&x));
231
232                    let _ = Box::<[usize]>::from_raw(slice);
233                }
234            }
235        }
236    }
237}
238
239enum PathIter<'a> {
240    Bits(BitsIter),
241    Slice(std::iter::Cloned<std::slice::Iter<'a, usize>>),
242}
243
244impl<'a> Iterator for PathIter<'a> {
245    type Item = usize;
246
247    #[inline]
248    fn next(&mut self) -> Option<usize> {
249        match self {
250            PathIter::Bits(bits) => bits.next(),
251            PathIter::Slice(slice) => slice.next(),
252        }
253    }
254
255    #[inline]
256    fn size_hint(&self) -> (usize, Option<usize>) {
257        match self {
258            PathIter::Bits(bits) => bits.size_hint(),
259            PathIter::Slice(slice) => slice.size_hint(),
260        }
261    }
262}
263
264/// Iterator over [`Id`] path components
265pub struct WidgetPathIter<'a>(PathIter<'a>);
266impl<'a> Iterator for WidgetPathIter<'a> {
267    type Item = usize;
268
269    #[inline]
270    fn next(&mut self) -> Option<usize> {
271        self.0.next()
272    }
273
274    #[inline]
275    fn size_hint(&self) -> (usize, Option<usize>) {
276        self.0.size_hint()
277    }
278}
279
280/// Widget identifier
281///
282/// All widgets are assigned an identifier which is unique within the window.
283/// This type may be tested for equality and order and may be iterated over as
284/// a "path" of "key" values.
285///
286/// Formatting an `Id` via [`Display`] prints the the path, for example
287/// `#1290a4`. Here, `#` represents the root; each following hexadecimal digit
288/// represents a path component except that digits `8-f` are combined with the
289/// following digit(s). Hence, the above path has components `1`, `2`, `90`,
290/// `a4`. To interpret these values, first subtract 8 from each digit but the
291/// last digit, then read as base-8: `[1, 2, 8, 20]`.
292///
293/// # Representation
294///
295/// This type is small (64-bit) and non-zero: `Option<Id>` has the same
296/// size as `Id`. It is also very cheap to `Clone`: usually only one `if`
297/// check, and in the worst case a pointer dereference and ref-count increment.
298/// Paths up to 14 digits long (as printed) are represented internally;
299/// beyond this limit a reference-counted stack allocation is used.
300///
301/// `Id` is neither `Send` nor `Sync`.
302///
303/// # Invalid state
304///
305/// When `Id` is [`Default`] constructed, it uses a special **invalid** state.
306/// Any attempt to use or compare such an invalid state will cause a panic.
307///
308/// Widgets are initially constructed with an invalid `Id`, then assigned an
309/// `Id` when configured (see [`Events::configure`]).
310/// In most cases values are persistent but this is not guaranteed (e.g.
311/// inserting or removing a child from a `List` widget will affect the
312/// identifiers of all following children). View-widgets assign path components
313/// based on the data key, thus *possibly* making identifiers persistent.
314///
315/// [`Display`]: std::fmt::Display
316/// [`ConfigCx::configure`]: crate::event::ConfigCx::configure
317/// [`Events::configure`]: crate::Events::configure
318#[allow(clippy::assigning_clones)]
319#[derive(Clone)]
320pub struct Id(IntOrPtr);
321
322// Encode lowest 48 bits of key into the low bits of a u64, returning also the encoded bit-length
323fn encode(key: usize) -> (u64, u8) {
324    debug_assert!(8 * size_of::<usize>() as u32 - key.leading_zeros() <= 64);
325    let mut x = key as u64 & 0x0000_FFFF_FFFF_FFFF;
326    let mut y = x & 7;
327    x >>= 3;
328    let mut shift = 4;
329    while x != 0 {
330        y |= (8 | (x & 7)) << shift;
331        x >>= 3;
332        shift += 4;
333    }
334    (y, shift)
335}
336
337#[inline]
338fn block_len(x: u64) -> u8 {
339    ((x & MASK_LEN) >> SHIFT_LEN) as u8
340}
341
342// Returns usize read from highest bits of x plus blocks used
343fn next_from_bits(mut x: u64) -> (usize, u8) {
344    const TAKE: u64 = 0x7000_0000_0000_0000;
345    const HIGH: u64 = 0x8000_0000_0000_0000;
346    let mut y = (x & TAKE) >> 60;
347    let mut c = 1;
348    while (x & HIGH) != 0 {
349        x <<= 4;
350        y = (y << 3) | ((x & TAKE) >> 60);
351        c += 1;
352    }
353    (y.cast(), c)
354}
355
356#[derive(Clone, Debug)]
357struct BitsIter(u8, u64);
358impl BitsIter {
359    fn new(bits: u64) -> Self {
360        assert!((bits & USE_MASK) == USE_BITS);
361        let len = block_len(bits);
362        BitsIter(len, bits & MASK_BITS)
363    }
364}
365impl Iterator for BitsIter {
366    type Item = usize;
367    fn next(&mut self) -> Option<usize> {
368        if self.0 == 0 {
369            return None;
370        }
371        let (next, blocks) = next_from_bits(self.1);
372        self.0 -= blocks;
373        self.1 <<= 4 * blocks;
374        Some(next)
375    }
376    fn size_hint(&self) -> (usize, Option<usize>) {
377        ((self.0 != 0) as usize, Some(self.0 as usize))
378    }
379}
380
381impl Id {
382    /// Identifier of the window
383    pub(crate) const ROOT: Self = Id(IntOrPtr::ROOT);
384
385    const INVALID: Self = Id(IntOrPtr::INVALID);
386
387    /// Is the identifier valid?
388    ///
389    /// Default-constructed identifiers are invalid. Comparing invalid ids is
390    /// considered a logic error and thus will panic in debug builds.
391    /// This method may be used to check an identifier's validity.
392    pub fn is_valid(&self) -> bool {
393        self.0.get() != Variant::Invalid
394    }
395
396    /// Iterate over path components
397    pub fn iter(&self) -> WidgetPathIter<'_> {
398        match self.0.get() {
399            Variant::Invalid => panic!("Id::iter: invalid"),
400            Variant::Int(x) => WidgetPathIter(PathIter::Bits(BitsIter::new(x))),
401            Variant::Slice(path) => WidgetPathIter(PathIter::Slice(path.iter().cloned())),
402        }
403    }
404
405    /// Get the path len (number of indices, not storage length)
406    pub fn path_len(&self) -> usize {
407        match self.0.get() {
408            Variant::Invalid => panic!("Id::path_len: invalid"),
409            Variant::Int(x) => BitsIter::new(x).count(),
410            Variant::Slice(path) => path.len(),
411        }
412    }
413
414    /// Returns true if `self` equals `id` or if `id` is a descendant of `self`
415    pub fn is_ancestor_of(&self, id: &Self) -> bool {
416        match (self.0.get(), id.0.get()) {
417            (Variant::Invalid, _) | (_, Variant::Invalid) => {
418                panic!("Id::is_ancestor_of: invalid")
419            }
420            (Variant::Slice(_), Variant::Int(_)) => {
421                // This combo will never be created where id is a child.
422                false
423            }
424            (Variant::Int(self_x), Variant::Int(child_x)) => {
425                let self_blocks = block_len(self_x);
426                let child_blocks = block_len(child_x);
427                if self_blocks > child_blocks {
428                    return false;
429                }
430
431                // self_blocks == 0 for ROOT, otherwise > 0
432                let shift = 4 * (BLOCKS - self_blocks) + 8;
433                shift == 64 || self_x >> shift == child_x >> shift
434            }
435            (Variant::Int(self_x), Variant::Slice(child)) => {
436                let iter = BitsIter::new(self_x);
437                iter.zip(child.iter()).all(|(a, b)| a == *b)
438            }
439            (Variant::Slice(self_path), Variant::Slice(child)) => child.starts_with(self_path),
440        }
441    }
442
443    /// Find the most-derived common ancestor
444    pub fn common_ancestor(&self, id: &Self) -> Self {
445        let mut r = Id::ROOT;
446        for (a, b) in self.iter().zip(id.iter()) {
447            if a != b {
448                break;
449            }
450            r = r.make_child(a);
451        }
452        r
453    }
454
455    pub fn iter_keys_after(&self, id: &Self) -> WidgetPathIter<'_> {
456        let mut self_iter = self.iter();
457        for v in id.iter() {
458            if self_iter.next() != Some(v) {
459                return WidgetPathIter(PathIter::Bits(BitsIter(0, 0)));
460            }
461        }
462        self_iter
463    }
464
465    /// Get first key in path of `self` path after `id`
466    ///
467    /// If the path of `self` starts with the path of `id`
468    /// (`id.is_ancestor_of(self)`) then this returns the *next* key in
469    /// `self`'s path (if any). Otherwise, this returns `None`.
470    pub fn next_key_after(&self, id: &Self) -> Option<usize> {
471        match (id.0.get(), self.0.get()) {
472            (Variant::Invalid, _) | (_, Variant::Invalid) => {
473                panic!("Id::next_key_after: invalid")
474            }
475            (Variant::Slice(_), Variant::Int(_)) => None,
476            (Variant::Int(parent_x), Variant::Int(child_x)) => {
477                let parent_blocks = block_len(parent_x);
478                let child_blocks = block_len(child_x);
479                if parent_blocks >= child_blocks {
480                    return None;
481                }
482
483                // parent_blocks == 0 for ROOT, otherwise > 0
484                let shift = 4 * (BLOCKS - parent_blocks) + 8;
485                if shift != 64 && parent_x >> shift != child_x >> shift {
486                    return None;
487                }
488
489                debug_assert!(child_blocks > 0);
490                let next_bits = (child_x & MASK_BITS) << (4 * parent_blocks);
491                Some(next_from_bits(next_bits).0)
492            }
493            (Variant::Int(parent_x), Variant::Slice(child_path)) => {
494                let iter = BitsIter::new(parent_x);
495                let mut child_iter = child_path.iter();
496                if iter.zip(&mut child_iter).all(|(a, b)| a == *b) {
497                    child_iter.next().cloned()
498                } else {
499                    None
500                }
501            }
502            (Variant::Slice(parent_path), Variant::Slice(child_path)) => {
503                if child_path.starts_with(parent_path) {
504                    child_path[parent_path.len()..].iter().next().cloned()
505                } else {
506                    None
507                }
508            }
509        }
510    }
511
512    /// Get the parent widget's identifier, if not root
513    pub fn parent(&self) -> Option<Id> {
514        match self.0.get() {
515            Variant::Invalid => None,
516            Variant::Int(x) => {
517                let mut bit_len = 4 * block_len(x);
518                while bit_len > 0 {
519                    bit_len -= 4;
520                    if bit_len > 0 && (x >> (64 - bit_len)) & 8 != 0 {
521                        continue;
522                    }
523
524                    let len = ((bit_len / 4) as u64) << SHIFT_LEN;
525                    let mask = MASK_BITS << (56 - bit_len);
526                    let id = (x & mask) | len | USE_BITS;
527                    return Some(Id(IntOrPtr::new_int(id)));
528                }
529                None
530            }
531            Variant::Slice(path) => {
532                if path.is_empty() {
533                    return None;
534                }
535
536                let len = path.len();
537                let path = &path[0..len - 1];
538
539                if len > BLOCKS as usize {
540                    Some(Id(IntOrPtr::new_iter(path.iter().cloned())))
541                } else {
542                    Some(make_id(path))
543                }
544            }
545        }
546    }
547
548    /// Make an identifier for the child with the given `key`
549    ///
550    /// Note: this is not a getter method. Calling multiple times with the same
551    /// `key` may or may not return the same value!
552    #[must_use]
553    pub fn make_child(&self, key: usize) -> Self {
554        match self.0.get() {
555            Variant::Invalid => panic!("Id::make_child: invalid"),
556            Variant::Int(self_x) => {
557                // TODO(opt): this bit-packing approach is designed for space-optimisation, but it may
558                // be better to use a simpler, less-compressed approach, possibly with u128 type.
559                let block_len = block_len(self_x);
560                let avail_blocks = BLOCKS - block_len;
561                // Note: zero is encoded with 1 block to force bump to len
562                let req_bits = (8 * size_of::<usize>() as u8 - key.leading_zeros() as u8).max(1);
563                if req_bits <= 3 * avail_blocks {
564                    let (bits, bit_len) = encode(key);
565                    let used_blocks = bit_len / 4;
566                    debug_assert_eq!(used_blocks, req_bits.div_ceil(3));
567                    let len = (block_len as u64 + used_blocks as u64) << SHIFT_LEN;
568                    let rest = bits << 4 * avail_blocks - bit_len + 8;
569                    let id = (self_x & MASK_BITS) | rest | len | USE_BITS;
570                    Id(IntOrPtr::new_int(id))
571                } else {
572                    Id(IntOrPtr::new_iter(BitsIter::new(self_x).chain(once(key))))
573                }
574            }
575            Variant::Slice(path) => Id(IntOrPtr::new_iter(path.iter().cloned().chain(once(key)))),
576        }
577    }
578
579    /// Convert to a [`NonZeroU64`] representation
580    ///
581    /// This conversion is infallible but not free.
582    ///
583    /// The result may be used in equality checks (with a *very* small risk of
584    /// false positive due to hash collision) and may be passed to
585    /// [`Self::try_from_u64`].
586    pub fn to_nzu64(&self) -> NonZeroU64 {
587        self.0.to_nzu64()
588    }
589
590    /// Try converting a `u64` to an `Id`
591    ///
592    /// This method is the inverse of [`Self::to_nzu64`]. Assuming that the
593    /// input `n` is the result of calling `id.to_nzu64().get()` for some `id`,
594    /// then this method will return:
595    ///
596    /// -   `Some(Id::INVALID)` where `!id.is_valid()`
597    /// -   `Some(id)` where `id` uses the internal (non-allocated) representation
598    /// -   `Some(id)` where `id` uses an allocated representation and the original `id` still
599    ///     exists (on the same thread).
600    /// -   `Some(id)` (probably) where `id` uses an allocated representation, has been freed then
601    ///     reconstructed (on the same thread) before calling this method.
602    ///     (There is a tiny chance of hash collision in this case.)
603    ///
604    /// This method will return `None` where:
605    ///
606    /// -   `n == 0`
607    /// -   The originating `id` used an allocating representation and has
608    ///     been deallocated without reconstruction
609    /// -   The originating `id` used an allocating representation and was
610    ///     constructed on another thread (excepting the case where an `Id` with
611    ///     the same hash was constructed on this thread)
612    ///
613    /// Bad / random inputs may yield either `None` or `Some(bad_id)` and in the
614    /// latter case operations on `bad_id` may panic, but are memory safe.
615    pub fn try_from_u64(n: u64) -> Option<Id> {
616        IntOrPtr::try_from_u64(n).map(Id)
617    }
618}
619
620impl PartialEq for Id {
621    fn eq(&self, rhs: &Self) -> bool {
622        match (self.0.get(), rhs.0.get()) {
623            (Variant::Invalid, _) | (_, Variant::Invalid) => panic!("Id::eq: invalid id"),
624            (Variant::Int(x), Variant::Int(y)) => x == y,
625            _ => self.iter().eq(rhs.iter()),
626        }
627    }
628}
629impl Eq for Id {}
630
631impl PartialEq<str> for Id {
632    fn eq(&self, rhs: &str) -> bool {
633        // TODO(opt): we don't have to format to test this
634        let formatted = format!("{self}");
635        formatted == rhs
636    }
637}
638impl PartialEq<&str> for Id {
639    fn eq(&self, rhs: &&str) -> bool {
640        self == *rhs
641    }
642}
643
644impl PartialOrd for Id {
645    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
646        Some(self.cmp(rhs))
647    }
648}
649
650impl Ord for Id {
651    fn cmp(&self, rhs: &Self) -> Ordering {
652        match (self.0.get(), rhs.0.get()) {
653            (Variant::Invalid, _) | (_, Variant::Invalid) => panic!("Id::cmp: invalid id"),
654            (Variant::Int(x), Variant::Int(y)) => x.cmp(&y),
655            _ => self.iter().cmp(rhs.iter()),
656        }
657    }
658}
659
660impl Hash for Id {
661    fn hash<H: Hasher>(&self, state: &mut H) {
662        match self.0.get() {
663            Variant::Invalid => (),
664            Variant::Int(x) => {
665                x.hash(state);
666            }
667            Variant::Slice(path) => {
668                path.hash(state);
669            }
670        }
671    }
672}
673
674impl PartialEq<Option<Id>> for Id {
675    #[inline]
676    fn eq(&self, rhs: &Option<Id>) -> bool {
677        rhs.as_ref().map(|id| id == self).unwrap_or(false)
678    }
679}
680
681impl<'a> PartialEq<Option<&'a Id>> for Id {
682    #[inline]
683    fn eq(&self, rhs: &Option<&'a Id>) -> bool {
684        rhs.map(|id| id == self).unwrap_or(false)
685    }
686}
687
688impl<'a> PartialEq<&'a Id> for Id {
689    #[inline]
690    fn eq(&self, rhs: &&Id) -> bool {
691        self == *rhs
692    }
693}
694
695impl<'a> PartialEq<&'a Option<Id>> for Id {
696    #[inline]
697    fn eq(&self, rhs: &&Option<Id>) -> bool {
698        self == *rhs
699    }
700}
701
702impl Default for Id {
703    fn default() -> Self {
704        Id::INVALID
705    }
706}
707
708impl fmt::Debug for Id {
709    #[inline]
710    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
711        write!(f, "Id({self})")
712    }
713}
714
715impl fmt::Display for Id {
716    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
717        match self.0.get() {
718            Variant::Invalid => write!(f, "#INVALID"),
719            Variant::Int(x) => {
720                let len = block_len(x);
721                if len == 0 {
722                    write!(f, "#")
723                } else {
724                    let bits = x >> (4 * (BLOCKS - len) + 8);
725                    write!(f, "#{1:0>0$x}", len as usize, bits)
726                }
727            }
728            Variant::Slice(path) => {
729                write!(f, "#")?;
730                for key in path {
731                    let (bits, bit_len) = encode(*key);
732                    write!(f, "{1:0>0$x}", bit_len as usize / 4, bits)?;
733                }
734                Ok(())
735            }
736        }
737    }
738}
739
740/// Convert to a `NodeId` using [`Id::to_nzu64`]
741///
742/// Use [`Id::try_from_u64`] for the inverse conversion.
743#[cfg(feature = "accesskit")]
744impl From<Id> for accesskit::NodeId {
745    #[inline]
746    fn from(id: Id) -> Self {
747        accesskit::NodeId(id.to_nzu64().get())
748    }
749}
750
751/// Convert to a `NodeId` using [`Id::to_nzu64`]
752///
753/// Use [`Id::try_from_u64`] for the inverse conversion.
754#[cfg(feature = "accesskit")]
755impl From<&Id> for accesskit::NodeId {
756    #[inline]
757    fn from(id: &Id) -> Self {
758        accesskit::NodeId(id.to_nzu64().get())
759    }
760}
761
762/// Types supporting conversion to [`Id`]
763///
764/// A method taking an `id: impl HasId` parameter supports an [`Id`],
765/// a reference to an [`Id`] (which is thus cloned),
766/// or a (mutable) reference to a widget.
767///
768/// Note: in some cases attempting to pass a widget reference does not pass
769/// borrow checks. In this case pass `widget.id()` explicitly.
770pub trait HasId {
771    fn has_id(self) -> Id;
772}
773
774impl HasId for Id {
775    #[inline]
776    fn has_id(self) -> Id {
777        self
778    }
779}
780
781impl HasId for &Id {
782    #[inline]
783    fn has_id(self) -> Id {
784        self.clone()
785    }
786}
787
788impl HasId for &mut Id {
789    #[inline]
790    fn has_id(self) -> Id {
791        self.clone()
792    }
793}
794
795fn make_id(seq: &[usize]) -> Id {
796    let mut id = Id::ROOT;
797    for x in seq {
798        id = id.make_child(*x);
799    }
800    id
801}
802
803#[cfg(test)]
804mod test {
805    use super::*;
806
807    #[test]
808    fn size_of_option_widget_id() {
809        use std::mem::size_of;
810        assert_eq!(size_of::<Id>(), 8);
811        assert_eq!(size_of::<Id>(), size_of::<Option<Id>>());
812    }
813
814    #[test]
815    fn test_partial_eq() {
816        assert_eq!(Id::ROOT, Id::ROOT);
817        let c1 = Id::ROOT.make_child(0).make_child(15);
818        let c2 = Id::ROOT.make_child(1).make_child(15);
819        let c3 = Id::ROOT.make_child(0).make_child(14);
820        let c4 = Id::ROOT.make_child(0).make_child(15);
821        assert!(c1 != c2);
822        assert!(c1 != c3);
823        assert!(c2 != c3);
824        assert_eq!(c1, c4);
825        assert!(c1 != Id::ROOT);
826
827        let d1 = Id(IntOrPtr::new_iter([0, 15].iter().cloned()));
828        let d2 = Id(IntOrPtr::new_iter([1, 15].iter().cloned()));
829        assert_eq!(c1, d1);
830        assert_eq!(c2, d2);
831        assert!(d1 != d2);
832        assert!(d1 != Id::ROOT);
833    }
834
835    #[test]
836    #[should_panic]
837    fn test_partial_eq_invalid_1() {
838        let _ = Id::INVALID == Id::INVALID;
839    }
840
841    #[test]
842    #[should_panic]
843    fn test_partial_eq_invalid_2() {
844        let _ = Id::ROOT == Id::INVALID;
845    }
846
847    #[test]
848    #[should_panic]
849    fn test_partial_eq_invalid_3() {
850        let _ = Id::INVALID == Id::ROOT;
851    }
852
853    #[test]
854    fn test_partial_eq_str() {
855        assert_eq!(Id::ROOT, "#");
856        assert!(Id::ROOT != "#0");
857        assert_eq!(Id::ROOT.make_child(0).make_child(15), "#097");
858        assert_eq!(Id::ROOT.make_child(1).make_child(15), "#197");
859        let c3 = Id::ROOT.make_child(0).make_child(14);
860        assert_eq!(c3, "#096");
861        assert!(c3 != "#097");
862    }
863
864    #[test]
865    fn test_ord() {
866        let root = Id::ROOT;
867        let c_0 = root.make_child(0);
868        let c_0_0 = c_0.make_child(0);
869        assert!(root < c_0);
870        assert!(c_0 < c_0_0);
871
872        let c_1 = root.make_child(1);
873        assert!(c_0_0 < c_1);
874        assert!(c_1 < root.make_child(8));
875
876        let d_0 = Id(IntOrPtr::new_iter([0].iter().cloned()));
877        let d_0_0 = Id(IntOrPtr::new_iter([0, 0].iter().cloned()));
878        let d_1 = Id(IntOrPtr::new_iter([1].iter().cloned()));
879        assert_eq!(d_0.cmp(&c_0), Ordering::Equal);
880        assert_eq!(d_0_0.cmp(&c_0_0), Ordering::Equal);
881        assert_eq!(d_1.cmp(&c_1), Ordering::Equal);
882        assert!(d_0 < d_0_0);
883        assert!(d_0_0 < d_1);
884    }
885
886    #[test]
887    #[should_panic]
888    fn test_ord_invalid() {
889        let _ = Id::INVALID < Id::ROOT;
890    }
891
892    #[test]
893    fn test_next_from_bits() {
894        const REST: u64 = 0x0FFF_FFFF_FFFF_FFFF;
895        assert_eq!(next_from_bits(0), (0, 1));
896        assert_eq!(next_from_bits(REST), (0, 1));
897        assert_eq!(next_from_bits((7 << 60) | REST), (7, 1));
898        assert_eq!(next_from_bits((0xB << 60) | (3 << 56)), (27, 2));
899        assert_eq!(
900            next_from_bits(0xC9A4_F300_0000_0000),
901            ((4 << 9) + (1 << 6) + (2 << 3) + 4, 4)
902        );
903    }
904
905    #[test]
906    fn text_bits_iter() {
907        fn as_vec(x: u64) -> Vec<usize> {
908            BitsIter::new(x).collect()
909        }
910        assert_eq!(as_vec(USE_BITS), Vec::<usize>::new());
911        assert_eq!(as_vec(0x3100_0000_0000_0011), vec![3]);
912        assert_eq!(as_vec(0x1A93_007F_0000_0071), vec![1, 139, 0, 0, 7]);
913    }
914
915    #[test]
916    fn test_parent() {
917        fn test(seq: &[usize]) {
918            let len = seq.len();
919            let id = make_id(&seq[..len - 1]);
920
921            if len == 0 {
922                assert_eq!(id.parent(), None);
923            } else {
924                let id2 = id.make_child(seq[len - 1]);
925                assert_eq!(id2.parent(), Some(id));
926            }
927        }
928
929        test(&[4]);
930        test(&[4, 0]);
931        test(&[0, 0, 0]);
932        test(&[0, 1, 0]);
933        test(&[9, 0, 1, 300]);
934        test(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0]);
935        test(&[313553, 13513, 13511631]);
936    }
937
938    #[test]
939    fn test_make_child() {
940        fn test(seq: &[usize], x: u64) {
941            let id = make_id(seq);
942            let v = id.to_nzu64().get();
943            if v != x {
944                panic!("test({seq:?}, {x:x}): found {v:x}");
945            }
946
947            // Every id is its own ancestor:
948            assert!(id.is_ancestor_of(&id));
949        }
950
951        test(&[], USE_BITS);
952        test(&[0, 0, 0], (3 << 4) | USE_BITS);
953        test(&[0, 1, 0], (3 << 4) | (1 << 56) | USE_BITS);
954        test(&[9, 0, 1, 300], 0x9101cd4000000071);
955        test(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0], 0x12345679091920e1);
956    }
957
958    #[test]
959    fn test_display() {
960        fn from_seq(seq: &[usize]) -> String {
961            format!("{}", make_id(seq))
962        }
963
964        assert_eq!(from_seq(&[]), "#");
965        assert_eq!(from_seq(&[0]), "#0");
966        assert_eq!(from_seq(&[1, 2, 3]), "#123");
967        assert_eq!(from_seq(&[5, 9, 13]), "#59195");
968        assert_eq!(from_seq(&[321]), "#d81");
969        assert_eq!(
970            from_seq(&[313553, 13513, 13511631]),
971            "#99ccba1bab91ebcadf97"
972        )
973    }
974
975    #[test]
976    fn test_is_ancestor() {
977        fn test(seq: &[usize], seq2: &[usize]) {
978            let id = make_id(seq);
979            let mut id2 = id.clone();
980            for x in seq2 {
981                id2 = id2.make_child(*x);
982            }
983            let next = seq2.iter().next().cloned();
984            assert_eq!(id.is_ancestor_of(&id2), next.is_some() || id == id2);
985            assert_eq!(id2.next_key_after(&id), next);
986        }
987
988        test(&[], &[]);
989        test(&[], &[1]);
990        test(&[], &[51930, 2, 18]);
991        test(&[5, 6, 0, 1, 1], &[]);
992        test(&[5, 6, 0, 1, 1], &[1, 1]);
993        test(&[8, 26], &[0]);
994        test(&[9, 9, 9, 9, 9, 9, 9], &[]);
995        test(&[9, 9, 9, 9, 9, 9, 9], &[6]);
996        test(&[9, 9, 9, 9, 9, 9, 9, 9], &[3]);
997        test(&[0, 2, 2, 0, 17], &[0]);
998    }
999
1000    #[test]
1001    fn test_not_ancestor() {
1002        fn test(seq: &[usize], seq2: &[usize]) {
1003            let id = make_id(seq);
1004            let id2 = make_id(seq2);
1005            assert_eq!(id.is_ancestor_of(&id2), false);
1006            assert_eq!(id2.next_key_after(&id), None);
1007        }
1008
1009        test(&[0], &[]);
1010        test(&[0], &[1]);
1011        test(&[2, 10, 1], &[2, 10]);
1012        test(&[0, 5, 2], &[0, 1, 5]);
1013    }
1014
1015    #[test]
1016    fn common_ancestor() {
1017        fn test(seq: &[usize], seq2: &[usize], seq3: &[usize]) {
1018            let id = make_id(seq);
1019            let id2 = make_id(seq2);
1020            assert_eq!(id.common_ancestor(&id2), make_id(seq3));
1021        }
1022
1023        test(&[0], &[], &[]);
1024        test(&[0], &[1, 2], &[]);
1025        test(&[0], &[0, 2], &[0]);
1026        test(&[2, 10, 1], &[2, 10], &[2, 10]);
1027        test(&[0, 5, 2], &[0, 5, 1], &[0, 5]);
1028    }
1029
1030    #[test]
1031    fn deduplicate_allocations() {
1032        let id1 = make_id(&[2, 6, 1, 1, 0, 13, 0, 100, 1000]);
1033        let id2 = make_id(&[2, 6, 1, 1, 0, 13, 0, 100, 1000]);
1034        assert_eq!(id1.0.0, id2.0.0);
1035    }
1036}