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 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}