1use crate::error::{Error, Result};
2use crate::types::{BandLayout, 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)]
63pub struct BandSetView<'a, T: Sample> {
64 width: u32,
65 height: u32,
66 depth: u32,
67 band_count: usize,
68 layout: BandLayout,
69 data: &'a [T],
70}
71
72impl<'a, T: Sample> BandSetView<'a, T> {
73 pub fn new(
74 width: u32,
75 height: u32,
76 depth: u32,
77 band_count: usize,
78 layout: BandLayout,
79 data: &'a [T],
80 ) -> Result<Self> {
81 if band_count == 0 {
82 return Err(Error::InvalidArgument(
83 "band_count must be greater than zero".into(),
84 ));
85 }
86
87 let band_sample_count = sample_count_from_dims(width, height, depth)?;
88 let expected_len = band_sample_count
89 .checked_mul(band_count)
90 .ok_or_else(|| Error::InvalidArgument("band set size overflows usize".into()))?;
91 if data.len() != expected_len {
92 return Err(Error::InvalidArgument(format!(
93 "band set slice length {} does not match width={width}, height={height}, depth={depth}, band_count={band_count}",
94 data.len()
95 )));
96 }
97
98 Ok(Self {
99 width,
100 height,
101 depth,
102 band_count,
103 layout,
104 data,
105 })
106 }
107
108 pub fn width(self) -> u32 {
109 self.width
110 }
111
112 pub fn height(self) -> u32 {
113 self.height
114 }
115
116 pub fn depth(self) -> u32 {
117 self.depth
118 }
119
120 pub fn band_count(self) -> usize {
121 self.band_count
122 }
123
124 pub fn layout(self) -> BandLayout {
125 self.layout
126 }
127
128 pub fn data(self) -> &'a [T] {
129 self.data
130 }
131
132 pub fn data_type(self) -> DataType {
133 T::data_type()
134 }
135
136 pub fn pixel_count(self) -> Result<usize> {
137 pixel_count_from_dims(self.width, self.height)
138 }
139
140 pub fn band_sample_count(self) -> Result<usize> {
141 sample_count_from_dims(self.width, self.height, self.depth)
142 }
143
144 pub fn value_count(self) -> Result<usize> {
145 self.band_sample_count()?
146 .checked_mul(self.band_count)
147 .ok_or_else(|| Error::InvalidArgument("band set size overflows usize".into()))
148 }
149
150 pub fn sample(self, band: usize, pixel: usize, dim: usize) -> T {
151 let depth = self.depth as usize;
152 let pixel_count = self.width as usize * self.height as usize;
153 let band_stride = pixel_count * depth;
154 let index = match self.layout {
155 BandLayout::Interleaved => (pixel * self.band_count + band) * depth + dim,
156 BandLayout::Bsq => band * band_stride + pixel * depth + dim,
157 };
158 self.data[index]
159 }
160}
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq)]
163pub struct MaskView<'a> {
164 width: u32,
165 height: u32,
166 data: &'a [u8],
167}
168
169impl<'a> MaskView<'a> {
170 pub fn new(width: u32, height: u32, data: &'a [u8]) -> Result<Self> {
171 let expected_len = pixel_count_from_dims(width, height)?;
172 if data.len() != expected_len {
173 return Err(Error::InvalidArgument(format!(
174 "mask slice length {} does not match width={width}, height={height}",
175 data.len()
176 )));
177 }
178 Ok(Self {
179 width,
180 height,
181 data,
182 })
183 }
184
185 pub fn width(self) -> u32 {
186 self.width
187 }
188
189 pub fn height(self) -> u32 {
190 self.height
191 }
192
193 pub fn data(self) -> &'a [u8] {
194 self.data
195 }
196
197 pub fn pixel_count(self) -> Result<usize> {
198 pixel_count_from_dims(self.width, self.height)
199 }
200
201 pub fn valid_count(self) -> usize {
202 self.data.iter().filter(|&&value| value != 0).count()
203 }
204}
205
206pub trait Sample: Copy + Default + private::Sealed + 'static {
207 fn data_type() -> DataType;
208 fn from_f64(value: f64) -> Self;
209 fn to_f64(self) -> f64;
210 fn read_vec(bytes: &[u8]) -> Result<Vec<Self>>;
211 fn into_pixel_data(values: Vec<Self>) -> PixelData;
212 fn append_le_bytes(self, out: &mut Vec<u8>);
213}
214
215macro_rules! impl_sample {
216 ($ty:ty, $size:expr, $variant:ident) => {
217 impl Sample for $ty {
218 fn data_type() -> DataType {
219 DataType::$variant
220 }
221
222 fn from_f64(value: f64) -> Self {
223 value as $ty
224 }
225
226 fn to_f64(self) -> f64 {
227 self as f64
228 }
229
230 fn read_vec(bytes: &[u8]) -> Result<Vec<Self>> {
231 let chunks = bytes.chunks_exact($size);
232 if !chunks.remainder().is_empty() {
233 return Err(Error::InvalidBlob(
234 "typed value payload length is not aligned to its data type".into(),
235 ));
236 }
237 Ok(chunks
238 .map(|chunk| <$ty>::from_le_bytes(chunk.try_into().unwrap()))
239 .collect())
240 }
241
242 fn into_pixel_data(values: Vec<Self>) -> PixelData {
243 PixelData::$variant(values)
244 }
245
246 fn append_le_bytes(self, out: &mut Vec<u8>) {
247 out.extend_from_slice(&self.to_le_bytes());
248 }
249 }
250 };
251}
252
253impl Sample for u8 {
254 fn data_type() -> DataType {
255 DataType::U8
256 }
257
258 fn from_f64(value: f64) -> Self {
259 value as u8
260 }
261
262 fn to_f64(self) -> f64 {
263 self as f64
264 }
265
266 fn read_vec(bytes: &[u8]) -> Result<Vec<Self>> {
267 Ok(bytes.to_vec())
268 }
269
270 fn into_pixel_data(values: Vec<Self>) -> PixelData {
271 PixelData::U8(values)
272 }
273
274 fn append_le_bytes(self, out: &mut Vec<u8>) {
275 out.push(self);
276 }
277}
278
279impl Sample for i8 {
280 fn data_type() -> DataType {
281 DataType::I8
282 }
283
284 fn from_f64(value: f64) -> Self {
285 value as i8
286 }
287
288 fn to_f64(self) -> f64 {
289 self as f64
290 }
291
292 fn read_vec(bytes: &[u8]) -> Result<Vec<Self>> {
293 Ok(bytes
294 .iter()
295 .map(|&byte| i8::from_le_bytes([byte]))
296 .collect())
297 }
298
299 fn into_pixel_data(values: Vec<Self>) -> PixelData {
300 PixelData::I8(values)
301 }
302
303 fn append_le_bytes(self, out: &mut Vec<u8>) {
304 out.push(self as u8);
305 }
306}
307
308impl_sample!(i16, 2, I16);
309impl_sample!(u16, 2, U16);
310impl_sample!(i32, 4, I32);
311impl_sample!(u32, 4, U32);
312impl_sample!(f32, 4, F32);
313impl_sample!(f64, 8, F64);
314
315pub fn pixel_count_from_dims(width: u32, height: u32) -> Result<usize> {
316 let width = usize::try_from(width)
317 .map_err(|_| Error::InvalidArgument("width does not fit in usize".into()))?;
318 let height = usize::try_from(height)
319 .map_err(|_| Error::InvalidArgument("height does not fit in usize".into()))?;
320 width
321 .checked_mul(height)
322 .ok_or_else(|| Error::InvalidArgument("pixel count overflows usize".into()))
323}
324
325pub fn sample_count_from_dims(width: u32, height: u32, depth: u32) -> Result<usize> {
326 if depth == 0 {
327 return Err(Error::InvalidArgument(
328 "depth must be greater than zero".into(),
329 ));
330 }
331 pixel_count_from_dims(width, height)?
332 .checked_mul(depth as usize)
333 .ok_or_else(|| Error::InvalidArgument("sample count overflows usize".into()))
334}
335
336pub fn read_values_as<T: Sample>(bytes: &[u8], source_type: DataType) -> Result<Vec<T>> {
337 if source_type == T::data_type() {
338 return T::read_vec(bytes);
339 }
340
341 read_typed_values(bytes, source_type)
342 .map(|values| values.into_iter().map(T::from_f64).collect())
343}
344
345pub fn coerce_f64_to_data_type(value: f64, data_type: DataType) -> f64 {
346 match data_type {
347 DataType::I8 => (value as i8) as f64,
348 DataType::U8 => (value as u8) as f64,
349 DataType::I16 => (value as i16) as f64,
350 DataType::U16 => (value as u16) as f64,
351 DataType::I32 => (value as i32) as f64,
352 DataType::U32 => (value as u32) as f64,
353 DataType::F32 => (value as f32) as f64,
354 DataType::F64 => value,
355 }
356}
357
358pub fn output_value<T: Sample>(value: f64, source_type: DataType) -> T {
359 if T::data_type() == DataType::F64 && source_type != DataType::F64 {
360 T::from_f64(coerce_f64_to_data_type(value, source_type))
361 } else {
362 T::from_f64(value)
363 }
364}
365
366pub fn read_scalar(bytes: &[u8], data_type: DataType) -> Result<f64> {
367 Ok(match data_type {
368 DataType::I8 => i8::from_le_bytes([bytes[0]]) as f64,
369 DataType::U8 => bytes[0] as f64,
370 DataType::I16 => i16::from_le_bytes(bytes.try_into().unwrap()) as f64,
371 DataType::U16 => u16::from_le_bytes(bytes.try_into().unwrap()) as f64,
372 DataType::I32 => i32::from_le_bytes(bytes.try_into().unwrap()) as f64,
373 DataType::U32 => u32::from_le_bytes(bytes.try_into().unwrap()) as f64,
374 DataType::F32 => f32::from_le_bytes(bytes.try_into().unwrap()) as f64,
375 DataType::F64 => f64::from_le_bytes(bytes.try_into().unwrap()),
376 })
377}
378
379pub fn read_typed_values(bytes: &[u8], data_type: DataType) -> Result<Vec<f64>> {
380 let mut out = Vec::with_capacity(bytes.len() / data_type.byte_len());
381 for chunk in bytes.chunks_exact(data_type.byte_len()) {
382 out.push(read_scalar(chunk, data_type)?);
383 }
384 if bytes.len() % data_type.byte_len() != 0 {
385 return Err(Error::InvalidBlob(
386 "typed value payload length is not aligned to its data type".into(),
387 ));
388 }
389 Ok(out)
390}
391
392pub fn append_value_as(out: &mut Vec<u8>, value: f64, data_type: DataType) {
393 match data_type {
394 DataType::I8 => out.push((value as i8) as u8),
395 DataType::U8 => out.push(value as u8),
396 DataType::I16 => out.extend_from_slice(&(value as i16).to_le_bytes()),
397 DataType::U16 => out.extend_from_slice(&(value as u16).to_le_bytes()),
398 DataType::I32 => out.extend_from_slice(&(value as i32).to_le_bytes()),
399 DataType::U32 => out.extend_from_slice(&(value as u32).to_le_bytes()),
400 DataType::F32 => out.extend_from_slice(&(value as f32).to_le_bytes()),
401 DataType::F64 => out.extend_from_slice(&value.to_le_bytes()),
402 }
403}
404
405pub fn count_valid_in_block(
406 mask: &[u8],
407 width: usize,
408 x0: usize,
409 y0: usize,
410 block_width: usize,
411 block_height: usize,
412) -> usize {
413 let mut count = 0usize;
414 for row in 0..block_height {
415 let row_offset = (y0 + row) * width + x0;
416 for col in 0..block_width {
417 count += usize::from(mask[row_offset + col] != 0);
418 }
419 }
420 count
421}
422
423pub fn bits_required(max_index: usize) -> u8 {
424 let mut bits = 0u8;
425 let mut value = max_index;
426 while value > 0 {
427 bits += 1;
428 value >>= 1;
429 }
430 bits
431}
432
433pub fn words_from_padded(bytes: &[u8]) -> Vec<u32> {
434 if bytes.is_empty() {
435 return Vec::new();
436 }
437 let mut padded = vec![0u8; bytes.len().div_ceil(4) * 4];
438 padded[..bytes.len()].copy_from_slice(bytes);
439 padded
440 .chunks_exact(4)
441 .map(|chunk| u32::from_le_bytes(chunk.try_into().unwrap()))
442 .collect()
443}
444
445pub fn fletcher32(bytes: &[u8]) -> u32 {
446 let mut sum1 = 0xffffu32;
447 let mut sum2 = 0xffffu32;
448 let mut words = bytes.len() / 2;
449 let mut index = 0usize;
450
451 while words > 0 {
452 let chunk = words.min(359);
453 words -= chunk;
454 for _ in 0..chunk {
455 sum1 += (bytes[index] as u32) << 8;
456 index += 1;
457 sum2 += sum1 + bytes[index] as u32;
458 sum1 += bytes[index] as u32;
459 index += 1;
460 }
461 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
462 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
463 }
464
465 if bytes.len() & 1 != 0 {
466 sum1 += (bytes[index] as u32) << 8;
467 sum2 += sum1;
468 }
469
470 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
471 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
472 (sum2 << 16) | (sum1 & 0xffff)
473}
474
475pub fn sample_index(pixel: usize, depth: usize, dim: usize) -> usize {
476 pixel * depth + dim
477}
478
479mod private {
480 pub trait Sealed {}
481
482 impl Sealed for i8 {}
483 impl Sealed for u8 {}
484 impl Sealed for i16 {}
485 impl Sealed for u16 {}
486 impl Sealed for i32 {}
487 impl Sealed for u32 {}
488 impl Sealed for f32 {}
489 impl Sealed for f64 {}
490}