1use crate::error::{Error, Result};
2use crate::types::{DataType, PixelData};
3
4#[derive(Debug, Clone, Copy, PartialEq)]
5pub struct RasterView<'a, T: Sample> {
6 width: u32,
7 height: u32,
8 depth: u32,
9 data: &'a [T],
10}
11
12impl<'a, T: Sample> RasterView<'a, T> {
13 pub fn new(width: u32, height: u32, depth: u32, data: &'a [T]) -> Result<Self> {
14 let expected_len = sample_count_from_dims(width, height, depth)?;
15 if data.len() != expected_len {
16 return Err(Error::InvalidArgument(format!(
17 "raster slice length {} does not match width={width}, height={height}, depth={depth}",
18 data.len()
19 )));
20 }
21 Ok(Self {
22 width,
23 height,
24 depth,
25 data,
26 })
27 }
28
29 pub fn width(self) -> u32 {
30 self.width
31 }
32
33 pub fn height(self) -> u32 {
34 self.height
35 }
36
37 pub fn depth(self) -> u32 {
38 self.depth
39 }
40
41 pub fn data(self) -> &'a [T] {
42 self.data
43 }
44
45 pub fn data_type(self) -> DataType {
46 T::data_type()
47 }
48
49 pub fn pixel_count(self) -> Result<usize> {
50 pixel_count_from_dims(self.width, self.height)
51 }
52
53 pub fn sample_count(self) -> Result<usize> {
54 sample_count_from_dims(self.width, self.height, self.depth)
55 }
56
57 pub fn sample(self, pixel: usize, dim: usize) -> T {
58 self.data[sample_index(pixel, self.depth as usize, dim)]
59 }
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub struct MaskView<'a> {
64 width: u32,
65 height: u32,
66 data: &'a [u8],
67}
68
69impl<'a> MaskView<'a> {
70 pub fn new(width: u32, height: u32, data: &'a [u8]) -> Result<Self> {
71 let expected_len = pixel_count_from_dims(width, height)?;
72 if data.len() != expected_len {
73 return Err(Error::InvalidArgument(format!(
74 "mask slice length {} does not match width={width}, height={height}",
75 data.len()
76 )));
77 }
78 Ok(Self {
79 width,
80 height,
81 data,
82 })
83 }
84
85 pub fn width(self) -> u32 {
86 self.width
87 }
88
89 pub fn height(self) -> u32 {
90 self.height
91 }
92
93 pub fn data(self) -> &'a [u8] {
94 self.data
95 }
96
97 pub fn pixel_count(self) -> Result<usize> {
98 pixel_count_from_dims(self.width, self.height)
99 }
100
101 pub fn valid_count(self) -> usize {
102 self.data.iter().filter(|&&value| value != 0).count()
103 }
104}
105
106pub trait Sample: Copy + Default + private::Sealed + 'static {
107 fn data_type() -> DataType;
108 fn from_f64(value: f64) -> Self;
109 fn to_f64(self) -> f64;
110 fn read_vec(bytes: &[u8]) -> Result<Vec<Self>>;
111 fn into_pixel_data(values: Vec<Self>) -> PixelData;
112 fn append_le_bytes(self, out: &mut Vec<u8>);
113}
114
115macro_rules! impl_sample {
116 ($ty:ty, $size:expr, $variant:ident) => {
117 impl Sample for $ty {
118 fn data_type() -> DataType {
119 DataType::$variant
120 }
121
122 fn from_f64(value: f64) -> Self {
123 value as $ty
124 }
125
126 fn to_f64(self) -> f64 {
127 self as f64
128 }
129
130 fn read_vec(bytes: &[u8]) -> Result<Vec<Self>> {
131 let chunks = bytes.chunks_exact($size);
132 if !chunks.remainder().is_empty() {
133 return Err(Error::InvalidBlob(
134 "typed value payload length is not aligned to its data type".into(),
135 ));
136 }
137 Ok(chunks
138 .map(|chunk| <$ty>::from_le_bytes(chunk.try_into().unwrap()))
139 .collect())
140 }
141
142 fn into_pixel_data(values: Vec<Self>) -> PixelData {
143 PixelData::$variant(values)
144 }
145
146 fn append_le_bytes(self, out: &mut Vec<u8>) {
147 out.extend_from_slice(&self.to_le_bytes());
148 }
149 }
150 };
151}
152
153impl Sample for u8 {
154 fn data_type() -> DataType {
155 DataType::U8
156 }
157
158 fn from_f64(value: f64) -> Self {
159 value as u8
160 }
161
162 fn to_f64(self) -> f64 {
163 self as f64
164 }
165
166 fn read_vec(bytes: &[u8]) -> Result<Vec<Self>> {
167 Ok(bytes.to_vec())
168 }
169
170 fn into_pixel_data(values: Vec<Self>) -> PixelData {
171 PixelData::U8(values)
172 }
173
174 fn append_le_bytes(self, out: &mut Vec<u8>) {
175 out.push(self);
176 }
177}
178
179impl Sample for i8 {
180 fn data_type() -> DataType {
181 DataType::I8
182 }
183
184 fn from_f64(value: f64) -> Self {
185 value as i8
186 }
187
188 fn to_f64(self) -> f64 {
189 self as f64
190 }
191
192 fn read_vec(bytes: &[u8]) -> Result<Vec<Self>> {
193 Ok(bytes
194 .iter()
195 .map(|&byte| i8::from_le_bytes([byte]))
196 .collect())
197 }
198
199 fn into_pixel_data(values: Vec<Self>) -> PixelData {
200 PixelData::I8(values)
201 }
202
203 fn append_le_bytes(self, out: &mut Vec<u8>) {
204 out.push(self as u8);
205 }
206}
207
208impl_sample!(i16, 2, I16);
209impl_sample!(u16, 2, U16);
210impl_sample!(i32, 4, I32);
211impl_sample!(u32, 4, U32);
212impl_sample!(f32, 4, F32);
213impl_sample!(f64, 8, F64);
214
215pub fn pixel_count_from_dims(width: u32, height: u32) -> Result<usize> {
216 let width = usize::try_from(width)
217 .map_err(|_| Error::InvalidArgument("width does not fit in usize".into()))?;
218 let height = usize::try_from(height)
219 .map_err(|_| Error::InvalidArgument("height does not fit in usize".into()))?;
220 width
221 .checked_mul(height)
222 .ok_or_else(|| Error::InvalidArgument("pixel count overflows usize".into()))
223}
224
225pub fn sample_count_from_dims(width: u32, height: u32, depth: u32) -> Result<usize> {
226 if depth == 0 {
227 return Err(Error::InvalidArgument(
228 "depth must be greater than zero".into(),
229 ));
230 }
231 pixel_count_from_dims(width, height)?
232 .checked_mul(depth as usize)
233 .ok_or_else(|| Error::InvalidArgument("sample count overflows usize".into()))
234}
235
236pub fn read_values_as<T: Sample>(bytes: &[u8], source_type: DataType) -> Result<Vec<T>> {
237 if source_type == T::data_type() {
238 return T::read_vec(bytes);
239 }
240
241 read_typed_values(bytes, source_type)
242 .map(|values| values.into_iter().map(T::from_f64).collect())
243}
244
245pub fn coerce_f64_to_data_type(value: f64, data_type: DataType) -> f64 {
246 match data_type {
247 DataType::I8 => (value as i8) as f64,
248 DataType::U8 => (value as u8) as f64,
249 DataType::I16 => (value as i16) as f64,
250 DataType::U16 => (value as u16) as f64,
251 DataType::I32 => (value as i32) as f64,
252 DataType::U32 => (value as u32) as f64,
253 DataType::F32 => (value as f32) as f64,
254 DataType::F64 => value,
255 }
256}
257
258pub fn output_value<T: Sample>(value: f64, source_type: DataType) -> T {
259 if T::data_type() == DataType::F64 && source_type != DataType::F64 {
260 T::from_f64(coerce_f64_to_data_type(value, source_type))
261 } else {
262 T::from_f64(value)
263 }
264}
265
266pub fn read_scalar(bytes: &[u8], data_type: DataType) -> Result<f64> {
267 Ok(match data_type {
268 DataType::I8 => i8::from_le_bytes([bytes[0]]) as f64,
269 DataType::U8 => bytes[0] as f64,
270 DataType::I16 => i16::from_le_bytes(bytes.try_into().unwrap()) as f64,
271 DataType::U16 => u16::from_le_bytes(bytes.try_into().unwrap()) as f64,
272 DataType::I32 => i32::from_le_bytes(bytes.try_into().unwrap()) as f64,
273 DataType::U32 => u32::from_le_bytes(bytes.try_into().unwrap()) as f64,
274 DataType::F32 => f32::from_le_bytes(bytes.try_into().unwrap()) as f64,
275 DataType::F64 => f64::from_le_bytes(bytes.try_into().unwrap()),
276 })
277}
278
279pub fn read_typed_values(bytes: &[u8], data_type: DataType) -> Result<Vec<f64>> {
280 let mut out = Vec::with_capacity(bytes.len() / data_type.byte_len());
281 for chunk in bytes.chunks_exact(data_type.byte_len()) {
282 out.push(read_scalar(chunk, data_type)?);
283 }
284 if bytes.len() % data_type.byte_len() != 0 {
285 return Err(Error::InvalidBlob(
286 "typed value payload length is not aligned to its data type".into(),
287 ));
288 }
289 Ok(out)
290}
291
292pub fn append_value_as(out: &mut Vec<u8>, value: f64, data_type: DataType) {
293 match data_type {
294 DataType::I8 => out.push((value as i8) as u8),
295 DataType::U8 => out.push(value as u8),
296 DataType::I16 => out.extend_from_slice(&(value as i16).to_le_bytes()),
297 DataType::U16 => out.extend_from_slice(&(value as u16).to_le_bytes()),
298 DataType::I32 => out.extend_from_slice(&(value as i32).to_le_bytes()),
299 DataType::U32 => out.extend_from_slice(&(value as u32).to_le_bytes()),
300 DataType::F32 => out.extend_from_slice(&(value as f32).to_le_bytes()),
301 DataType::F64 => out.extend_from_slice(&value.to_le_bytes()),
302 }
303}
304
305pub fn count_valid_in_block(
306 mask: &[u8],
307 width: usize,
308 x0: usize,
309 y0: usize,
310 block_width: usize,
311 block_height: usize,
312) -> usize {
313 let mut count = 0usize;
314 for row in 0..block_height {
315 let row_offset = (y0 + row) * width + x0;
316 for col in 0..block_width {
317 count += usize::from(mask[row_offset + col] != 0);
318 }
319 }
320 count
321}
322
323pub fn bits_required(max_index: usize) -> u8 {
324 let mut bits = 0u8;
325 let mut value = max_index;
326 while value > 0 {
327 bits += 1;
328 value >>= 1;
329 }
330 bits
331}
332
333pub fn words_from_padded(bytes: &[u8]) -> Vec<u32> {
334 if bytes.is_empty() {
335 return Vec::new();
336 }
337 let mut padded = vec![0u8; bytes.len().div_ceil(4) * 4];
338 padded[..bytes.len()].copy_from_slice(bytes);
339 padded
340 .chunks_exact(4)
341 .map(|chunk| u32::from_le_bytes(chunk.try_into().unwrap()))
342 .collect()
343}
344
345pub fn fletcher32(bytes: &[u8]) -> u32 {
346 let mut sum1 = 0xffffu32;
347 let mut sum2 = 0xffffu32;
348 let mut words = bytes.len() / 2;
349 let mut index = 0usize;
350
351 while words > 0 {
352 let chunk = words.min(359);
353 words -= chunk;
354 for _ in 0..chunk {
355 sum1 += (bytes[index] as u32) << 8;
356 index += 1;
357 sum2 += sum1 + bytes[index] as u32;
358 sum1 += bytes[index] as u32;
359 index += 1;
360 }
361 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
362 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
363 }
364
365 if bytes.len() & 1 != 0 {
366 sum1 += (bytes[index] as u32) << 8;
367 sum2 += sum1;
368 }
369
370 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
371 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
372 (sum2 << 16) | (sum1 & 0xffff)
373}
374
375pub fn sample_index(pixel: usize, depth: usize, dim: usize) -> usize {
376 pixel * depth + dim
377}
378
379mod private {
380 pub trait Sealed {}
381
382 impl Sealed for i8 {}
383 impl Sealed for u8 {}
384 impl Sealed for i16 {}
385 impl Sealed for u16 {}
386 impl Sealed for i32 {}
387 impl Sealed for u32 {}
388 impl Sealed for f32 {}
389 impl Sealed for f64 {}
390}