store_ref_scanner/
hbm.rs

1#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2pub struct HalfBytesMask(pub [u8; 16]);
3
4#[allow(clippy::as_conversions, clippy::zero_prefixed_literal)]
5impl HalfBytesMask {
6    pub const B32_REVSHA256: HalfBytesMask =
7        HalfBytesMask([0, 0, 0, 0, 0, 0, 255, 3, 0, 0, 0, 0, 222, 127, 207, 7]);
8
9    pub const B64_BLAKE2B256: HalfBytesMask = HalfBytesMask([
10        0, 0, 0, 0, 0, 8, 255, 3, 254, 255, 255, 135, 254, 255, 255, 7,
11    ]);
12
13    pub const DFL_REST: HalfBytesMask = HalfBytesMask([
14        0, 0, 0, 0, 0, 104, 255, 163, 254, 255, 255, 135, 254, 255, 255, 7,
15    ]);
16
17    #[inline]
18    pub const fn from_expanded(x: [bool; 128]) -> Self {
19        let mut ret = [0u8; 16];
20        let mut idx = 0;
21        while idx < 16 {
22            let fin = idx * 8;
23            let mut idx2 = 0;
24            while idx2 < 8 {
25                if x[fin + idx2] {
26                    ret[idx] += (1 << idx2) as u8;
27                }
28                idx2 += 1;
29            }
30            idx += 1;
31        }
32        Self(ret)
33    }
34
35    /// create a mask by allowing all characters via the mask which are included in the given string
36    pub fn from_bytes(s: &[u8]) -> Self {
37        s.iter().fold(Self([0u8; 16]), |mut ret, &i| {
38            ret.set(i, true);
39            ret
40        })
41    }
42
43    pub const fn into_expanded(self) -> [bool; 128] {
44        let Self(ihbm) = self;
45        let mut ret = [false; 128];
46        let mut idx = 0;
47        while idx < 16 {
48            let fin = idx * 8;
49            let curi = ihbm[idx];
50            let mut idx2 = 0;
51            while idx2 < 8 {
52                ret[fin + idx2] = (curi >> idx2) & 0b1 != 0;
53                idx2 += 1;
54            }
55            idx += 1;
56        }
57        ret
58    }
59
60    pub fn contains(&self, byte: u8) -> bool {
61        if byte >= 0x80 {
62            false
63        } else {
64            (self.0[usize::from(byte / 8)] >> u32::from(byte % 8)) & 0b1 != 0
65        }
66    }
67
68    pub fn set(&mut self, byte: u8, allow: bool) {
69        if byte >= 0x80 {
70            if cfg!(debug_assertions) {
71                panic!(
72                    "tried to manipulate invalid byte {:?} in HalfBytesMask",
73                    byte
74                );
75            } else {
76                return;
77            }
78        }
79        let block = &mut self.0[usize::from(byte / 8)];
80        let bitpat = (1 << u32::from(byte % 8)) as u8;
81        if allow {
82            *block |= bitpat;
83        } else {
84            *block &= !bitpat;
85        }
86    }
87
88    #[cfg(test)]
89    fn count_ones(&self) -> u8 {
90        self.0
91            .iter()
92            .map(|i| i.count_ones())
93            .sum::<u32>()
94            .try_into()
95            .unwrap()
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn maskbase() {
105        assert_eq!(HalfBytesMask::B32_REVSHA256.count_ones(), 32);
106        assert_eq!(HalfBytesMask::B64_BLAKE2B256.count_ones(), 64);
107    }
108
109    #[test]
110    fn non_ascii() {
111        for i in 0x80..=0xff {
112            assert!(!HalfBytesMask::DFL_REST.contains(i));
113        }
114    }
115
116    #[test]
117    fn dflmask() {
118        assert_eq!(
119            HalfBytesMask::from_expanded(
120                [
121                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
124                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126                ]
127                .map(|i| i != 0)
128            ),
129            Default::default(),
130        );
131
132        assert_eq!(
133            HalfBytesMask::from_expanded(
134                [
135                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
136                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
137                    1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
138                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1,
139                    1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
140                ]
141                .map(|i| i != 0)
142            ),
143            HalfBytesMask::B32_REVSHA256,
144        );
145
146        assert_eq!(
147            HalfBytesMask::from_expanded(
148                [
149                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
150                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1,
151                    1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
152                    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1,
153                    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
154                ]
155                .map(|i| i != 0)
156            ),
157            HalfBytesMask::B64_BLAKE2B256,
158        );
159
160        assert_eq!(
161            HalfBytesMask::from_bytes(
162                b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-._?="
163            ),
164            HalfBytesMask::DFL_REST,
165        );
166    }
167}