1use crate::layout::{SampleBits, SampleParts};
2use image_texel::Texel;
3
4#[derive(Clone, Copy, Debug)]
6pub struct FromBits {
7 pub(crate) begin: usize,
8 pub(crate) len: usize,
9}
10
11macro_rules! from_bits {
12 ($bits:ident = { $($variant:pat => $($value:expr)+);* }) => {
13 match $bits {
14 $($variant => from_bits!(@ $($value);*)),*,
15 }
16 };
17 (@ $v0:expr) => {
18 [Some(FromBits::from_range($v0)), None, None, None, None, None, None, None]
19 };
20 (@ $v0:expr; $v1:expr) => {
21 [Some(FromBits::from_range($v0)), Some(FromBits::from_range($v1)), None, None, None, None, None, None]
22 };
23 (@ $v0:expr; $v1:expr; $v2:expr) => {
24 [
25 Some(FromBits::from_range($v0)),
26 Some(FromBits::from_range($v1)),
27 Some(FromBits::from_range($v2)),
28 None,
29 None,
30 None,
31 None,
32 None,
33 ]
34 };
35 (@ $v0:expr; $v1:expr; $v2:expr; $v3:expr) => {
36 [
37 Some(FromBits::from_range($v0)),
38 Some(FromBits::from_range($v1)),
39 Some(FromBits::from_range($v2)),
40 Some(FromBits::from_range($v3)),
41 None,
42 None,
43 None,
44 None,
45 ]
46 };
47 (@ $v0:expr; $v1:expr; $v2:expr; $v3:expr; $v4:expr; $v5:expr) => {
48 [
49 Some(FromBits::from_range($v0)),
50 Some(FromBits::from_range($v1)),
51 Some(FromBits::from_range($v2)),
52 Some(FromBits::from_range($v3)),
53 Some(FromBits::from_range($v4)),
54 Some(FromBits::from_range($v5)),
55 None,
56 None,
57 ]
58 };
59 (@ $v0:expr; $v1:expr; $v2:expr; $v3:expr; $v4:expr; $v5:expr; $v6:expr; $v7:expr) => {
60 [
61 Some(FromBits::from_range($v0)),
62 Some(FromBits::from_range($v1)),
63 Some(FromBits::from_range($v2)),
64 Some(FromBits::from_range($v3)),
65 Some(FromBits::from_range($v4)),
66 Some(FromBits::from_range($v5)),
67 Some(FromBits::from_range($v6)),
68 Some(FromBits::from_range($v7)),
69 ]
70 };
71}
72
73impl FromBits {
74 const NO_BITS: Self = FromBits { begin: 0, len: 0 };
75
76 const fn from_range(range: core::ops::Range<usize>) -> Self {
77 FromBits {
78 begin: range.start,
79 len: range.end - range.start,
80 }
81 }
82
83 pub(crate) fn for_pixel(bits: SampleBits, parts: SampleParts) -> [Self; 4] {
84 let mut vals = [Self::NO_BITS; 4];
85
86 let bits = Self::bits(bits);
87 let channels = parts.channels();
88
89 for (bits, (channel, pos)) in bits.zip(channels) {
90 if let Some(_) = channel {
91 vals[pos as usize] = bits;
92 }
93 }
94
95 vals
96 }
97
98 pub(crate) fn for_pixels<const N: usize>(
99 bits: SampleBits,
100 parts: SampleParts,
101 ) -> [[Self; 4]; N] {
102 let mut vals = [[Self::NO_BITS; 4]; N];
103
104 let mut bits = Self::bits(bits);
105
106 for vals in vals.iter_mut() {
107 let channels = parts.channels().filter_map(|(ch, p)| Some((ch?, p)));
108
109 for (_, pos) in channels {
110 if let Some(bits) = bits.next() {
111 vals[pos as usize] = bits;
112 }
113 }
114 }
115
116 vals
117 }
118
119 pub(crate) const fn mask(self) -> u32 {
120 ((-1i64 as u64) ^ u32::MAX as u64).rotate_left(self.len as u32) as u32
121 }
122
123 fn bits(bits: SampleBits) -> impl Iterator<Item = Self> {
124 use SampleBits::*;
125
126 let filled: [Option<Self>; 8] = from_bits!(bits = {
127 Int8 | UInt8 => 0..8;
128 UInt332 => 0..3 3..6 6..8;
129 UInt233 => 0..2 2..5 5..8;
130 Int16 | UInt16 => 0..16;
131 UInt4x2 => 0..4 4..8;
132 UInt4x4 => 0..4 4..8 8..12 12..16;
133 UInt4x6 => 0..4 4..8 8..12 12..16 16..20 20..24;
134 UInt_444 => 4..8 8..12 12..16;
135 UInt444_ => 0..4 4..8 8..12;
136 UInt565 => 0..5 5..11 11..16;
137 Int8x2 | UInt8x2 => 0..8 8..16;
138 Int8x3 | UInt8x3 => 0..8 8..16 16..24;
139 Int8x4 | UInt8x4 => 0..8 8..16 16..24 24..32;
140 UInt8x6 => 0..8 8..16 16..24 24..32 32..40 40..48;
141 Int16x2 | UInt16x2 => 0..16 16..32;
142 Int16x3 | UInt16x3 => 0..16 16..32 32..48;
143 Int16x4 | UInt16x4 => 0..16 16..32 32..48 48..64;
144 UInt16x6 => 0..16 16..32 32..48 48..64 64..80 80..96;
145 UInt1010102 => 0..10 10..20 20..30 30..32;
146 UInt2101010 => 0..2 2..12 12..22 22..32;
147 UInt101010_ => 0..10 10..20 20..30;
148 UInt_101010 => 2..12 12..22 22..32;
149 Float16x4 => 0..16 16..32 32..48 48..64;
150 Float32 => 0..32;
151 Float32x2 => 0..32 32..64;
152 Float32x3 => 0..32 32..64 64..96;
153 Float32x4 => 0..32 32..64 64..96 96..128;
154 Float32x6 => 0..32 32..64 64..96 96..128 128..160 160..192;
155 UInt1x8 => 0..1 1..2 2..3 3..4 4..5 5..6 6..7 7..8;
156 UInt2x4 => 0..2 2..4 4..6 6..8
157 });
158
159 filled.into_iter().filter_map(|x| x)
160 }
161
162 #[inline]
170 pub(crate) fn extract_as_lsb<T>(&self, texel: Texel<T>, val: &T) -> u32 {
171 let ne_bytes = texel.to_bytes(core::slice::from_ref(val));
175 let start_byte = self.begin / 8;
176 let from_bytes = &ne_bytes[start_byte.min(ne_bytes.len())..];
177 assert!(self.len <= 32);
178
179 let shift = self.begin - start_byte * 8;
180 let bitlen = self.len + shift;
181 let copylen = if bitlen % 8 == 0 {
182 bitlen / 8
183 } else {
184 bitlen / 8 + 1
185 };
186
187 let mut be_bytes = [0; 8];
188 let initlen = copylen.min(8).min(from_bytes.len());
189 be_bytes[..initlen].copy_from_slice(&from_bytes[..initlen]);
190
191 let val = u64::from_be_bytes(be_bytes) >> (64 - bitlen).min(63);
192 val as u32 & self.mask()
194 }
195
196 pub(crate) fn insert_as_lsb<T>(&self, texel: Texel<T>, val: &mut T, bits: u32) {
197 let ne_bytes = texel.to_mut_bytes(core::slice::from_mut(val));
199 let start_byte = self.begin / 8;
200 let bytestart = start_byte.min(ne_bytes.len());
201 let texel_bytes = &mut ne_bytes[bytestart..];
202
203 let shift = self.begin - start_byte * 8;
204 let bitlen = self.len + shift;
205 let copylen = if bitlen % 8 == 0 {
206 bitlen / 8
207 } else {
208 bitlen / 8 + 1
209 };
210
211 let mut be_bytes = [0; 8];
212 let initlen = copylen.min(8).min(texel_bytes.len());
213 be_bytes[..initlen].copy_from_slice(&texel_bytes[..initlen]);
214
215 let mask = ((-1i64 as u64) ^ u32::MAX as u64).rotate_left((self.len as u32).min(32))
216 & (u32::MAX as u64);
217
218 let bitshift = (64 - bitlen).min(63);
219 let newval = (u64::from_be_bytes(be_bytes) & !(mask << bitshift))
220 | (u64::from(bits) & mask) << bitshift;
221
222 be_bytes = newval.to_be_bytes();
223 texel_bytes[..initlen].copy_from_slice(&be_bytes[..initlen]);
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use super::FromBits;
230 use image_texel::AsTexel;
231
232 #[test]
233 fn bit_extraction() {
234 fn extract_simple(r: core::ops::Range<usize>, val: &u8) -> u32 {
235 FromBits {
236 begin: r.start,
237 len: r.len(),
238 }
239 .extract_as_lsb(u8::texel(), &val)
240 }
241
242 let val = 0b1000_1010u8;
243 assert_eq!(extract_simple(0..1, &val), 1);
244 assert_eq!(extract_simple(1..2, &val), 0);
245 assert_eq!(extract_simple(2..3, &val), 0);
246 assert_eq!(extract_simple(6..7, &val), 1);
247 assert_eq!(extract_simple(0..7, &val), val as u32 >> 1);
248 assert_eq!(extract_simple(1..8, &val), (val & 0x7f) as u32);
249
250 assert_eq!(extract_simple(0..0, &val), 0);
251 assert_eq!(extract_simple(1..1, &val), 0);
252 }
253
254 #[test]
255 fn bit_insertion() {
256 fn insert_simple(r: core::ops::Range<usize>, bits: u32, val: &mut u8) -> u8 {
258 let before = *val;
259 FromBits {
260 begin: r.start,
261 len: r.len(),
262 }
263 .insert_as_lsb(u8::texel(), val, bits);
264 before ^ *val
265 }
266
267 let mut val = 0b1000_1010u8;
268 assert_eq!(insert_simple(0..1, 1, &mut val), 0);
269 assert_eq!(insert_simple(1..2, 0, &mut val), 0);
270 assert_eq!(insert_simple(2..3, 0, &mut val), 0);
271 assert_eq!(insert_simple(6..7, 1, &mut val), 0);
272 assert_eq!(insert_simple(0..7, val as u32 >> 1, &mut val), 0);
273 assert_eq!(insert_simple(1..8, (val & 0x7f) as u32, &mut val), 0);
274
275 assert_eq!(insert_simple(0..0, 0, &mut val), 0);
276 assert_eq!(insert_simple(1..1, 0, &mut val), 0);
277 }
278}