1use core::{fmt, mem};
2
3#[derive(Copy, Clone, PartialEq, Eq)]
5#[repr(transparent)]
6pub(crate) struct Tag(pub(super) u8);
7impl Tag {
8    pub(crate) const EMPTY: Tag = Tag(0b1111_1111);
10
11    pub(crate) const DELETED: Tag = Tag(0b1000_0000);
13
14    #[inline]
16    pub(crate) const fn is_full(self) -> bool {
17        self.0 & 0x80 == 0
18    }
19
20    #[inline]
22    pub(crate) const fn is_special(self) -> bool {
23        self.0 & 0x80 != 0
24    }
25
26    #[inline]
28    pub(crate) const fn special_is_empty(self) -> bool {
29        debug_assert!(self.is_special());
30        self.0 & 0x01 != 0
31    }
32
33    #[inline]
35    #[allow(clippy::cast_possible_truncation)]
36    pub(crate) const fn full(hash: u64) -> Tag {
37        const MIN_HASH_LEN: usize = if mem::size_of::<usize>() < mem::size_of::<u64>() {
39            mem::size_of::<usize>()
40        } else {
41            mem::size_of::<u64>()
42        };
43
44        let top7 = hash >> (MIN_HASH_LEN * 8 - 7);
49        Tag((top7 & 0x7f) as u8) }
51}
52impl fmt::Debug for Tag {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        if self.is_special() {
55            if self.special_is_empty() {
56                f.pad("EMPTY")
57            } else {
58                f.pad("DELETED")
59            }
60        } else {
61            f.debug_tuple("full").field(&(self.0 & 0x7F)).finish()
62        }
63    }
64}
65
66pub(crate) trait TagSliceExt {
68    fn fill_tag(&mut self, tag: Tag);
70
71    #[inline]
73    fn fill_empty(&mut self) {
74        self.fill_tag(Tag::EMPTY)
75    }
76}
77impl TagSliceExt for [Tag] {
78    #[inline]
79    fn fill_tag(&mut self, tag: Tag) {
80        unsafe { self.as_mut_ptr().write_bytes(tag.0, self.len()) }
82    }
83}