1use crate::error::{Error, Result};
2use crate::types::{BandLayout, DataType, PixelData};
3
4#[derive(Debug, Clone, Copy, PartialEq)]
6pub struct RasterView<'a, T: Sample> {
7 width: u32,
8 height: u32,
9 depth: u32,
10 data: &'a [T],
11}
12
13impl<'a, T: Sample> RasterView<'a, T> {
14 pub fn new(width: u32, height: u32, depth: u32, data: &'a [T]) -> Result<Self> {
20 let expected_len = sample_count_from_dims(width, height, depth)?;
21 if data.len() != expected_len {
22 return Err(Error::InvalidArgument(
23 "raster slice length does not match its dimensions",
24 ));
25 }
26 Ok(Self {
27 width,
28 height,
29 depth,
30 data,
31 })
32 }
33
34 pub fn width(self) -> u32 {
36 self.width
37 }
38
39 pub fn height(self) -> u32 {
41 self.height
42 }
43
44 pub fn depth(self) -> u32 {
46 self.depth
47 }
48
49 pub fn data(self) -> &'a [T] {
51 self.data
52 }
53
54 pub fn data_type(self) -> DataType {
56 T::DATA_TYPE
57 }
58
59 pub fn pixel_count(self) -> Result<usize> {
61 pixel_count_from_dims(self.width, self.height)
62 }
63
64 pub fn sample_count(self) -> Result<usize> {
66 sample_count_from_dims(self.width, self.height, self.depth)
67 }
68
69 pub fn sample(self, pixel: usize, dim: usize) -> T {
74 self.data[sample_index(pixel, self.depth as usize, dim)]
75 }
76}
77
78#[derive(Debug, Clone, Copy, PartialEq)]
80pub struct BandSetView<'a, T: Sample> {
81 width: u32,
82 height: u32,
83 depth: u32,
84 band_count: usize,
85 layout: BandLayout,
86 data: &'a [T],
87 pixel_count: usize,
88 pixel_stride: usize,
89 band_stride: usize,
90}
91
92impl<'a, T: Sample> BandSetView<'a, T> {
93 pub fn new(
99 width: u32,
100 height: u32,
101 depth: u32,
102 band_count: usize,
103 layout: BandLayout,
104 data: &'a [T],
105 ) -> Result<Self> {
106 if band_count == 0 {
107 return Err(Error::InvalidArgument(
108 "band_count must be greater than zero",
109 ));
110 }
111
112 let band_sample_count = sample_count_from_dims(width, height, depth)?;
113 let pixel_count = pixel_count_from_dims(width, height)?;
114 let pixel_stride = (depth as usize)
115 .checked_mul(band_count)
116 .ok_or(Error::SizeOverflow("interleaved pixel stride"))?;
117 let expected_len = band_sample_count
118 .checked_mul(band_count)
119 .ok_or(Error::SizeOverflow("band set value count"))?;
120 if data.len() != expected_len {
121 return Err(Error::InvalidArgument(
122 "band set slice length does not match its dimensions",
123 ));
124 }
125
126 Ok(Self {
127 width,
128 height,
129 depth,
130 band_count,
131 layout,
132 data,
133 pixel_count,
134 pixel_stride,
135 band_stride: band_sample_count,
136 })
137 }
138
139 pub fn width(self) -> u32 {
141 self.width
142 }
143
144 pub fn height(self) -> u32 {
146 self.height
147 }
148
149 pub fn depth(self) -> u32 {
151 self.depth
152 }
153
154 pub fn band_count(self) -> usize {
156 self.band_count
157 }
158
159 pub fn layout(self) -> BandLayout {
161 self.layout
162 }
163
164 pub fn data(self) -> &'a [T] {
166 self.data
167 }
168
169 pub fn data_type(self) -> DataType {
171 T::DATA_TYPE
172 }
173
174 pub fn pixel_count(self) -> Result<usize> {
176 Ok(self.pixel_count)
177 }
178
179 pub fn band_sample_count(self) -> Result<usize> {
181 Ok(self.band_stride)
182 }
183
184 pub fn value_count(self) -> Result<usize> {
186 self.band_sample_count()?
187 .checked_mul(self.band_count)
188 .ok_or(Error::SizeOverflow("band set value count"))
189 }
190
191 pub fn sample(self, band: usize, pixel: usize, dim: usize) -> T {
196 let depth = self.depth as usize;
197 let index = match self.layout {
198 BandLayout::Interleaved => pixel * self.pixel_stride + band * depth + dim,
199 BandLayout::Bsq => band * self.band_stride + pixel * depth + dim,
200 };
201 self.data[index]
202 }
203}
204
205#[derive(Debug, Clone, Copy, PartialEq, Eq)]
207pub struct MaskView<'a> {
208 width: u32,
209 height: u32,
210 data: &'a [u8],
211}
212
213impl<'a> MaskView<'a> {
214 pub fn new(width: u32, height: u32, data: &'a [u8]) -> Result<Self> {
220 let expected_len = pixel_count_from_dims(width, height)?;
221 if data.len() != expected_len {
222 return Err(Error::InvalidArgument(
223 "mask slice length does not match its dimensions",
224 ));
225 }
226 Ok(Self {
227 width,
228 height,
229 data,
230 })
231 }
232
233 pub fn width(self) -> u32 {
235 self.width
236 }
237
238 pub fn height(self) -> u32 {
240 self.height
241 }
242
243 pub fn data(self) -> &'a [u8] {
245 self.data
246 }
247
248 pub fn pixel_count(self) -> Result<usize> {
250 pixel_count_from_dims(self.width, self.height)
251 }
252
253 pub fn valid_count(self) -> usize {
255 self.data.iter().filter(|&&value| value != 0).count()
256 }
257}
258
259pub trait Sample: Copy + Default + private::Sealed + 'static {
264 const DATA_TYPE: DataType;
266 const IS_INTEGER: bool;
268
269 fn from_f64(value: f64) -> Self;
271 fn to_f64(self) -> f64;
273 fn read_le(bytes: &[u8]) -> Result<Self>;
275 fn write_le(self, out: &mut Vec<u8>);
277 fn into_pixel_data(values: Vec<Self>) -> PixelData;
279
280 fn read_vec(bytes: &[u8]) -> Result<Vec<Self>> {
282 let size = Self::DATA_TYPE.byte_len();
283 let chunks = bytes.chunks_exact(size);
284 if !chunks.remainder().is_empty() {
285 return Err(Error::invalid_blob(
286 "typed value payload length is not aligned to its data type",
287 ));
288 }
289 let mut values = Vec::new();
290 values
291 .try_reserve_exact(bytes.len() / size)
292 .map_err(|_| Error::AllocationFailed("typed sample buffer"))?;
293 for chunk in chunks {
294 values.push(Self::read_le(chunk)?);
295 }
296 Ok(values)
297 }
298}
299
300macro_rules! impl_sample {
301 ($ty:ty, $variant:ident, $is_integer:expr) => {
302 impl Sample for $ty {
303 const DATA_TYPE: DataType = DataType::$variant;
304 const IS_INTEGER: bool = $is_integer;
305
306 fn from_f64(value: f64) -> Self {
307 value as $ty
308 }
309
310 fn to_f64(self) -> f64 {
311 self as f64
312 }
313
314 fn read_le(bytes: &[u8]) -> Result<Self> {
315 let bytes = bytes.try_into().map_err(|_| {
316 Error::invalid_blob("typed scalar byte length does not match its data type")
317 })?;
318 Ok(<$ty>::from_le_bytes(bytes))
319 }
320
321 fn write_le(self, out: &mut Vec<u8>) {
322 out.extend_from_slice(&self.to_le_bytes());
323 }
324
325 fn into_pixel_data(values: Vec<Self>) -> PixelData {
326 PixelData::$variant(values)
327 }
328 }
329 };
330}
331
332impl_sample!(i8, I8, true);
333impl_sample!(u8, U8, true);
334impl_sample!(i16, I16, true);
335impl_sample!(u16, U16, true);
336impl_sample!(i32, I32, true);
337impl_sample!(u32, U32, true);
338impl_sample!(f32, F32, false);
339impl_sample!(f64, F64, false);
340
341#[macro_export]
342macro_rules! dispatch_data_type {
344 ($data_type:expr, $sample:ident => $body:block) => {{
345 match $data_type {
346 $crate::DataType::I8 => {
347 type $sample = i8;
348 $body
349 }
350 $crate::DataType::U8 => {
351 type $sample = u8;
352 $body
353 }
354 $crate::DataType::I16 => {
355 type $sample = i16;
356 $body
357 }
358 $crate::DataType::U16 => {
359 type $sample = u16;
360 $body
361 }
362 $crate::DataType::I32 => {
363 type $sample = i32;
364 $body
365 }
366 $crate::DataType::U32 => {
367 type $sample = u32;
368 $body
369 }
370 $crate::DataType::F32 => {
371 type $sample = f32;
372 $body
373 }
374 $crate::DataType::F64 => {
375 type $sample = f64;
376 $body
377 }
378 }
379 }};
380}
381
382pub fn pixel_count_from_dims(width: u32, height: u32) -> Result<usize> {
384 let width = usize::try_from(width).map_err(|_| Error::SizeOverflow("width as usize"))?;
385 let height = usize::try_from(height).map_err(|_| Error::SizeOverflow("height as usize"))?;
386 width
387 .checked_mul(height)
388 .ok_or(Error::SizeOverflow("pixel count"))
389}
390
391pub fn sample_count_from_dims(width: u32, height: u32, depth: u32) -> Result<usize> {
393 if depth == 0 {
394 return Err(Error::InvalidArgument("depth must be greater than zero"));
395 }
396 pixel_count_from_dims(width, height)?
397 .checked_mul(depth as usize)
398 .ok_or(Error::SizeOverflow("sample count"))
399}
400
401pub fn read_values_as<T: Sample>(bytes: &[u8], source_type: DataType) -> Result<Vec<T>> {
403 if source_type == T::DATA_TYPE {
404 return T::read_vec(bytes);
405 }
406
407 let sample_size = source_type.byte_len();
408 if bytes.len() % sample_size != 0 {
409 return Err(Error::invalid_blob(
410 "typed value payload length is not aligned to its data type",
411 ));
412 }
413 let mut out = Vec::new();
414 out.try_reserve_exact(bytes.len() / sample_size)
415 .map_err(|_| Error::AllocationFailed("converted sample buffer"))?;
416 crate::dispatch_data_type!(source_type, Source => {
417 for chunk in bytes.chunks_exact(sample_size) {
418 out.push(T::from_f64(Source::read_le(chunk)?.to_f64()));
419 }
420 });
421 Ok(out)
422}
423
424pub fn coerce_f64_to_data_type(value: f64, data_type: DataType) -> f64 {
426 crate::dispatch_data_type!(data_type, Target => { Target::from_f64(value).to_f64() })
427}
428
429pub fn output_value<T: Sample>(value: f64, source_type: DataType) -> T {
431 if T::DATA_TYPE == DataType::F64 && source_type != DataType::F64 {
432 T::from_f64(coerce_f64_to_data_type(value, source_type))
433 } else {
434 T::from_f64(value)
435 }
436}
437
438pub fn read_scalar(bytes: &[u8], data_type: DataType) -> Result<f64> {
440 crate::dispatch_data_type!(data_type, Source => { Ok(Source::read_le(bytes)?.to_f64()) })
441}
442
443pub fn read_typed_values(bytes: &[u8], data_type: DataType) -> Result<Vec<f64>> {
445 let sample_size = data_type.byte_len();
446 if bytes.len() % sample_size != 0 {
447 return Err(Error::invalid_blob(
448 "typed value payload length is not aligned to its data type",
449 ));
450 }
451 let mut out = Vec::new();
452 out.try_reserve_exact(bytes.len() / sample_size)
453 .map_err(|_| Error::AllocationFailed("promoted sample buffer"))?;
454 for chunk in bytes.chunks_exact(sample_size) {
455 out.push(read_scalar(chunk, data_type)?);
456 }
457 Ok(out)
458}
459
460pub fn append_value_as(out: &mut Vec<u8>, value: f64, data_type: DataType) {
462 crate::dispatch_data_type!(data_type, Target => {
463 Target::from_f64(value).write_le(out);
464 });
465}
466
467pub fn count_valid_in_block(
472 mask: &[u8],
473 width: usize,
474 x0: usize,
475 y0: usize,
476 block_width: usize,
477 block_height: usize,
478) -> usize {
479 let mut count = 0usize;
480 for row in 0..block_height {
481 let row_offset = (y0 + row) * width + x0;
482 for col in 0..block_width {
483 count += usize::from(mask[row_offset + col] != 0);
484 }
485 }
486 count
487}
488
489pub fn bits_required(max_index: usize) -> u8 {
491 let mut bits = 0u8;
492 let mut value = max_index;
493 while value > 0 {
494 bits += 1;
495 value >>= 1;
496 }
497 bits
498}
499
500pub fn words_from_padded(bytes: &[u8]) -> Result<Vec<u32>> {
505 if bytes.is_empty() {
506 return Ok(Vec::new());
507 }
508 let mut words = Vec::new();
509 words
510 .try_reserve_exact(bytes.len().div_ceil(4))
511 .map_err(|_| Error::AllocationFailed("bit-stuffed word buffer"))?;
512
513 let mut chunks = bytes.chunks_exact(4);
514 for chunk in &mut chunks {
515 words.push(u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]));
516 }
517 let remainder = chunks.remainder();
518 if !remainder.is_empty() {
519 let mut word = [0u8; 4];
520 word[..remainder.len()].copy_from_slice(remainder);
521 words.push(u32::from_le_bytes(word));
522 }
523 Ok(words)
524}
525
526pub fn fletcher32(bytes: &[u8]) -> u32 {
528 let mut sum1 = 0xffffu32;
529 let mut sum2 = 0xffffu32;
530 let mut words = bytes.len() / 2;
531 let mut index = 0usize;
532
533 while words > 0 {
534 let chunk = words.min(359);
535 words -= chunk;
536 for _ in 0..chunk {
537 sum1 += (bytes[index] as u32) << 8;
538 index += 1;
539 sum2 += sum1 + bytes[index] as u32;
540 sum1 += bytes[index] as u32;
541 index += 1;
542 }
543 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
544 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
545 }
546
547 if bytes.len() & 1 != 0 {
548 sum1 += (bytes[index] as u32) << 8;
549 sum2 += sum1;
550 }
551
552 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
553 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
554 (sum2 << 16) | (sum1 & 0xffff)
555}
556
557#[cfg(test)]
558mod tests {
559 use super::words_from_padded;
560
561 #[test]
562 fn converts_aligned_and_partial_little_endian_words_without_a_padding_buffer() {
563 assert!(words_from_padded(&[]).unwrap().is_empty());
564 assert_eq!(words_from_padded(&[1]).unwrap(), vec![1]);
565 assert_eq!(words_from_padded(&[1, 2, 3, 4]).unwrap(), vec![0x0403_0201]);
566 assert_eq!(
567 words_from_padded(&[1, 2, 3, 4, 5]).unwrap(),
568 vec![0x0403_0201, 5]
569 );
570 }
571}
572
573pub fn sample_index(pixel: usize, depth: usize, dim: usize) -> usize {
575 pixel * depth + dim
576}
577
578mod private {
579 pub trait Sealed {}
580
581 impl Sealed for i8 {}
582 impl Sealed for u8 {}
583 impl Sealed for i16 {}
584 impl Sealed for u16 {}
585 impl Sealed for i32 {}
586 impl Sealed for u32 {}
587 impl Sealed for f32 {}
588 impl Sealed for f64 {}
589}