1use crate::error::{Error, Result};
4use grib_core::bit::{read_bit, BitReader};
5pub use grib_core::data::{
6 ComplexPackingParams, DataRepresentation, SimplePackingParams, SpatialDifferencingParams,
7};
8
9pub trait DecodeSample: Copy + Sized {
11 fn from_f64(value: f64) -> Self;
12 fn nan() -> Self;
13}
14
15impl DecodeSample for f32 {
16 fn from_f64(value: f64) -> Self {
17 value as f32
18 }
19
20 fn nan() -> Self {
21 f32::NAN
22 }
23}
24
25impl DecodeSample for f64 {
26 fn from_f64(value: f64) -> Self {
27 value
28 }
29
30 fn nan() -> Self {
31 f64::NAN
32 }
33}
34
35pub fn decode_field(
37 data_section: &[u8],
38 representation: &DataRepresentation,
39 bitmap_section: Option<&[u8]>,
40 num_grid_points: usize,
41) -> Result<Vec<f64>> {
42 if data_section.len() < 5 || data_section[4] != 7 {
43 return Err(Error::InvalidSection {
44 section: data_section.get(4).copied().unwrap_or(7),
45 reason: "not a data section".into(),
46 });
47 }
48
49 decode_payload(
50 &data_section[5..],
51 representation,
52 bitmap_section,
53 num_grid_points,
54 )
55}
56
57pub fn decode_field_into<T: DecodeSample>(
60 data_section: &[u8],
61 representation: &DataRepresentation,
62 bitmap_section: Option<&[u8]>,
63 num_grid_points: usize,
64 out: &mut [T],
65) -> Result<()> {
66 if data_section.len() < 5 || data_section[4] != 7 {
67 return Err(Error::InvalidSection {
68 section: data_section.get(4).copied().unwrap_or(7),
69 reason: "not a data section".into(),
70 });
71 }
72
73 decode_payload_into(
74 &data_section[5..],
75 representation,
76 bitmap_section,
77 num_grid_points,
78 out,
79 )
80}
81
82pub(crate) fn decode_payload(
83 payload: &[u8],
84 representation: &DataRepresentation,
85 bitmap_section: Option<&[u8]>,
86 num_grid_points: usize,
87) -> Result<Vec<f64>> {
88 let mut values = vec![0.0; num_grid_points];
89 decode_payload_into(
90 payload,
91 representation,
92 bitmap_section,
93 num_grid_points,
94 &mut values,
95 )?;
96 Ok(values)
97}
98
99pub(crate) fn decode_payload_into<T: DecodeSample>(
100 payload: &[u8],
101 representation: &DataRepresentation,
102 bitmap_section: Option<&[u8]>,
103 num_grid_points: usize,
104 out: &mut [T],
105) -> Result<()> {
106 if out.len() != num_grid_points {
107 return Err(Error::DataLengthMismatch {
108 expected: num_grid_points,
109 actual: out.len(),
110 });
111 }
112
113 let expected_values = match representation {
114 DataRepresentation::SimplePacking(params) => params.encoded_values,
115 DataRepresentation::ComplexPacking(params) => params.encoded_values,
116 DataRepresentation::Unsupported(template) => {
117 return Err(Error::UnsupportedDataTemplate(*template));
118 }
119 };
120 match bitmap_section {
121 Some(bitmap_payload) => {
122 let present_values = count_bitmap_present_points(bitmap_payload, num_grid_points)?;
123 if expected_values != present_values {
124 return Err(Error::DataLengthMismatch {
125 expected: present_values,
126 actual: expected_values,
127 });
128 }
129 }
130 None if expected_values != num_grid_points => {
131 return Err(Error::DataLengthMismatch {
132 expected: num_grid_points,
133 actual: expected_values,
134 });
135 }
136 None => {}
137 }
138
139 let mut output = OutputCursor::new(out, bitmap_section);
140 match representation {
141 DataRepresentation::SimplePacking(params) => {
142 unpack_simple_into(payload, params, expected_values, &mut output)?
143 }
144 DataRepresentation::ComplexPacking(params) => {
145 unpack_complex_into(payload, params, &mut output)?
146 }
147 DataRepresentation::Unsupported(_) => unreachable!(),
148 }
149 output.finish()
150}
151
152pub fn bitmap_payload(section_bytes: &[u8]) -> Result<Option<&[u8]>> {
154 if section_bytes.len() < 6 {
155 return Err(Error::InvalidSection {
156 section: 6,
157 reason: format!("expected at least 6 bytes, got {}", section_bytes.len()),
158 });
159 }
160 if section_bytes[4] != 6 {
161 return Err(Error::InvalidSection {
162 section: section_bytes[4],
163 reason: "not a bitmap section".into(),
164 });
165 }
166
167 match section_bytes[5] {
168 255 => Ok(None),
169 0 => Ok(Some(§ion_bytes[6..])),
170 indicator => Err(Error::UnsupportedBitmapIndicator(indicator)),
171 }
172}
173
174pub(crate) fn count_bitmap_present_points(
175 bitmap_payload: &[u8],
176 num_grid_points: usize,
177) -> Result<usize> {
178 let full_bytes = num_grid_points / 8;
179 let remaining_bits = num_grid_points % 8;
180 let required_bytes = full_bytes + usize::from(remaining_bits > 0);
181 if bitmap_payload.len() < required_bytes {
182 return Err(Error::DataLengthMismatch {
183 expected: required_bytes,
184 actual: bitmap_payload.len(),
185 });
186 }
187
188 let mut present = bitmap_payload[..full_bytes]
189 .iter()
190 .map(|byte| byte.count_ones() as usize)
191 .sum();
192 if remaining_bits > 0 {
193 let mask = u8::MAX << (8 - remaining_bits);
194 present += (bitmap_payload[full_bytes] & mask).count_ones() as usize;
195 }
196
197 Ok(present)
198}
199
200pub fn unpack_simple(
202 data_bytes: &[u8],
203 params: &SimplePackingParams,
204 num_values: usize,
205) -> Result<Vec<f64>> {
206 let mut values = vec![0.0; num_values];
207 let mut output = OutputCursor::new(&mut values, None);
208 unpack_simple_into(data_bytes, params, num_values, &mut output)?;
209 output.finish()?;
210 Ok(values)
211}
212
213fn unpack_simple_into<T: DecodeSample>(
214 data_bytes: &[u8],
215 params: &SimplePackingParams,
216 num_values: usize,
217 output: &mut OutputCursor<'_, T>,
218) -> Result<()> {
219 let bits = params.bits_per_value as usize;
220 let binary_factor = 2.0_f64.powi(params.binary_scale as i32);
221 let decimal_factor = 10.0_f64.powi(-(params.decimal_scale as i32));
222 let reference = params.reference_value as f64;
223 if bits == 0 {
224 let constant = T::from_f64(scale_decoded_value(
225 reference,
226 0.0,
227 binary_factor,
228 decimal_factor,
229 ));
230 for _ in 0..num_values {
231 output.push_present(constant)?;
232 }
233 return Ok(());
234 }
235 if bits > u64::BITS as usize {
236 return Err(Error::UnsupportedPackingWidth(params.bits_per_value));
237 }
238
239 let required_bits = bits
240 .checked_mul(num_values)
241 .ok_or_else(|| Error::Other("bit count overflow during unpacking".into()))?;
242 let required_bytes = required_bits.div_ceil(8);
243 if data_bytes.len() < required_bytes {
244 return Err(Error::Truncated {
245 offset: data_bytes.len() as u64,
246 });
247 }
248
249 let mut reader = BitReader::new(data_bytes);
250
251 for _ in 0..num_values {
252 let packed = reader.read(bits)?;
253 output.push_present(T::from_f64(scale_decoded_value(
254 reference,
255 packed as f64,
256 binary_factor,
257 decimal_factor,
258 )))?;
259 }
260
261 Ok(())
262}
263
264#[cfg(test)]
265fn unpack_complex(data_bytes: &[u8], params: &ComplexPackingParams) -> Result<Vec<f64>> {
266 let mut values = vec![0.0; params.encoded_values];
267 let mut output = OutputCursor::new(&mut values, None);
268 unpack_complex_into(data_bytes, params, &mut output)?;
269 output.finish()?;
270 Ok(values)
271}
272
273fn unpack_complex_into<T: DecodeSample>(
274 data_bytes: &[u8],
275 params: &ComplexPackingParams,
276 output: &mut OutputCursor<'_, T>,
277) -> Result<()> {
278 if params.num_groups == 0 {
279 return Err(Error::InvalidSection {
280 section: 5,
281 reason: "complex packing requires at least one group".into(),
282 });
283 }
284
285 let mut reader = BitReader::new(data_bytes);
286 let mut spatial = params
287 .spatial_differencing
288 .map(|spatial| read_spatial_descriptors(&mut reader, spatial))
289 .transpose()?
290 .map(SpatialRestoreState::new);
291
292 let layout = GroupReaderLayout::new(reader.bit_offset(), params)?;
293 let mut reference_reader = BitReader::with_offset(data_bytes, layout.reference_offset);
294 let mut width_reader = BitReader::with_offset(data_bytes, layout.width_offset);
295 let mut length_reader = BitReader::with_offset(data_bytes, layout.length_offset);
296 let mut value_reader = BitReader::with_offset(data_bytes, layout.value_offset);
297 let binary_factor = 2.0_f64.powi(params.binary_scale as i32);
298 let decimal_factor = 10.0_f64.powi(-(params.decimal_scale as i32));
299 let reference = params.reference_value as f64;
300 let mut actual_total = 0usize;
301
302 for group_index in 0..params.num_groups {
303 let group_reference = reference_reader.read(params.group_reference_bits as usize)?;
304 let width_delta = width_reader.read(params.group_width_bits as usize)?;
305 let group_width = usize::from(params.group_width_reference)
306 .checked_add(width_delta as usize)
307 .ok_or_else(|| Error::Other("group width overflow".into()))?;
308 let group_length = read_group_length(&mut length_reader, params, group_index)?;
309
310 actual_total = actual_total
311 .checked_add(group_length)
312 .ok_or_else(|| Error::Other("group length overflow".into()))?;
313
314 if group_width == 0 {
315 let raw_value = decode_constant_group_value(
316 group_reference,
317 params.group_reference_bits as usize,
318 params.missing_value_management,
319 )?;
320 for _ in 0..group_length {
321 let value = spatial
322 .as_mut()
323 .map_or(Ok(raw_value), |state| state.restore(raw_value))?;
324 output.push_present(scale_complex_value(
325 reference,
326 binary_factor,
327 decimal_factor,
328 value,
329 ))?;
330 }
331 continue;
332 }
333
334 if group_width > u64::BITS as usize {
335 return Err(Error::UnsupportedPackingWidth(group_width as u8));
336 }
337
338 let group_reference = i64::try_from(group_reference)
339 .map_err(|_| Error::Other("group reference exceeds i64 range".into()))?;
340 for _ in 0..group_length {
341 let packed = value_reader.read(group_width)?;
342 let value = decode_group_value(
343 group_reference,
344 packed,
345 group_width,
346 params.missing_value_management,
347 )?;
348 let value = spatial
349 .as_mut()
350 .map_or(Ok(value), |state| state.restore(value))?;
351 output.push_present(scale_complex_value(
352 reference,
353 binary_factor,
354 decimal_factor,
355 value,
356 ))?;
357 }
358 }
359
360 if actual_total != params.encoded_values {
361 return Err(Error::DataLengthMismatch {
362 expected: params.encoded_values,
363 actual: actual_total,
364 });
365 }
366
367 if output.values_written() != params.encoded_values {
368 return Err(Error::DataLengthMismatch {
369 expected: params.encoded_values,
370 actual: output.values_written(),
371 });
372 }
373
374 if let Some(spatial) = spatial {
375 spatial.finish()?;
376 }
377
378 Ok(())
379}
380
381fn read_group_length(
382 reader: &mut BitReader<'_>,
383 params: &ComplexPackingParams,
384 group_index: usize,
385) -> Result<usize> {
386 if params.scaled_group_length_bits as usize > u64::BITS as usize {
387 return Err(Error::UnsupportedPackingWidth(
388 params.scaled_group_length_bits,
389 ));
390 }
391
392 if group_index + 1 == params.num_groups {
393 return Ok(params.true_length_last_group as usize);
394 }
395
396 let scaled = reader
397 .read(params.scaled_group_length_bits as usize)?
398 .checked_mul(u64::from(params.group_length_increment))
399 .ok_or_else(|| Error::Other("group length overflow".into()))?;
400 let length = u64::from(params.group_length_reference)
401 .checked_add(scaled)
402 .ok_or_else(|| Error::Other("group length overflow".into()))?;
403 usize::try_from(length).map_err(|_| Error::Other("group length overflow".into()))
404}
405
406fn read_spatial_descriptors(
407 reader: &mut BitReader<'_>,
408 params: SpatialDifferencingParams,
409) -> Result<SpatialDescriptors> {
410 if params.descriptor_octets == 0 {
411 return Err(Error::InvalidSection {
412 section: 5,
413 reason: "spatial differencing requires at least one descriptor octet".into(),
414 });
415 }
416
417 let bit_count = usize::from(params.descriptor_octets) * 8;
418 if bit_count > u64::BITS as usize {
419 return Err(Error::Other(
420 "spatial differencing descriptors wider than 8 octets are not supported".into(),
421 ));
422 }
423
424 let first_value = reader.read_signed(bit_count)?;
425 let second_value = if params.order == 2 {
426 Some(reader.read_signed(bit_count)?)
427 } else {
428 None
429 };
430 for _ in usize::from(params.order.min(2))..params.order as usize {
431 let _ = reader.read_signed(bit_count)?;
432 }
433 let overall_minimum = reader.read_signed(bit_count)?;
434
435 Ok(SpatialDescriptors {
436 order: params.order,
437 first_value,
438 second_value,
439 overall_minimum,
440 })
441}
442
443fn decode_constant_group_value(
444 group_reference: u64,
445 group_reference_bits: usize,
446 missing_value_management: u8,
447) -> Result<Option<i64>> {
448 if is_missing_code(
449 group_reference,
450 group_reference_bits,
451 missing_value_management,
452 MissingKind::Primary,
453 )? || is_missing_code(
454 group_reference,
455 group_reference_bits,
456 missing_value_management,
457 MissingKind::Secondary,
458 )? {
459 return Ok(None);
460 }
461
462 let value = i64::try_from(group_reference)
463 .map_err(|_| Error::Other("group reference exceeds i64 range".into()))?;
464 Ok(Some(value))
465}
466
467fn decode_group_value(
468 group_reference: i64,
469 packed: u64,
470 group_width: usize,
471 missing_value_management: u8,
472) -> Result<Option<i64>> {
473 if is_missing_code(
474 packed,
475 group_width,
476 missing_value_management,
477 MissingKind::Primary,
478 )? || is_missing_code(
479 packed,
480 group_width,
481 missing_value_management,
482 MissingKind::Secondary,
483 )? {
484 return Ok(None);
485 }
486
487 let packed =
488 i64::try_from(packed).map_err(|_| Error::Other("packed value exceeds i64 range".into()))?;
489 let value = group_reference
490 .checked_add(packed)
491 .ok_or_else(|| Error::Other("decoded complex packing value overflow".into()))?;
492 Ok(Some(value))
493}
494
495fn is_missing_code(
496 value: u64,
497 bit_width: usize,
498 missing_value_management: u8,
499 kind: MissingKind,
500) -> Result<bool> {
501 let required_mode = match kind {
502 MissingKind::Primary => 1,
503 MissingKind::Secondary => 2,
504 };
505 if missing_value_management < required_mode {
506 return Ok(false);
507 }
508
509 let Some(code) = missing_code(bit_width, kind)? else {
510 return Ok(false);
511 };
512 Ok(value == code)
513}
514
515fn missing_code(bit_width: usize, kind: MissingKind) -> Result<Option<u64>> {
516 if bit_width == 0 {
517 return Ok(None);
518 }
519 if bit_width > u64::BITS as usize {
520 return Err(Error::UnsupportedPackingWidth(bit_width as u8));
521 }
522
523 let max_value = if bit_width == u64::BITS as usize {
524 u64::MAX
525 } else {
526 (1u64 << bit_width) - 1
527 };
528
529 let code = match kind {
530 MissingKind::Primary => max_value,
531 MissingKind::Secondary => max_value.saturating_sub(1),
532 };
533 Ok(Some(code))
534}
535
536fn scale_complex_value<T: DecodeSample>(
537 reference: f64,
538 binary_factor: f64,
539 decimal_factor: f64,
540 value: Option<i64>,
541) -> T {
542 match value {
543 Some(value) => T::from_f64(scale_decoded_value(
544 reference,
545 value as f64,
546 binary_factor,
547 decimal_factor,
548 )),
549 None => T::nan(),
550 }
551}
552
553fn scale_decoded_value(
554 reference: f64,
555 packed_delta: f64,
556 binary_factor: f64,
557 decimal_factor: f64,
558) -> f64 {
559 (reference + packed_delta * binary_factor) * decimal_factor
560}
561
562fn bitmap_bit(bitmap_payload: &[u8], index: usize) -> Result<bool> {
563 read_bit(bitmap_payload, index).map_err(|_| Error::DataLengthMismatch {
564 expected: index / 8 + 1,
565 actual: bitmap_payload.len(),
566 })
567}
568
569struct GroupReaderLayout {
570 reference_offset: usize,
571 width_offset: usize,
572 length_offset: usize,
573 value_offset: usize,
574}
575
576impl GroupReaderLayout {
577 fn new(start_bit_offset: usize, params: &ComplexPackingParams) -> Result<Self> {
578 if params.group_reference_bits as usize > u64::BITS as usize {
579 return Err(Error::UnsupportedPackingWidth(params.group_reference_bits));
580 }
581 if params.group_width_bits as usize > u64::BITS as usize {
582 return Err(Error::UnsupportedPackingWidth(params.group_width_bits));
583 }
584 if params.scaled_group_length_bits as usize > u64::BITS as usize {
585 return Err(Error::UnsupportedPackingWidth(
586 params.scaled_group_length_bits,
587 ));
588 }
589
590 let reference_offset = start_bit_offset;
591 let width_offset = align_bit_offset(add_group_bits(
592 reference_offset,
593 params.num_groups,
594 params.group_reference_bits as usize,
595 )?)?;
596 let length_offset = align_bit_offset(add_group_bits(
597 width_offset,
598 params.num_groups,
599 params.group_width_bits as usize,
600 )?)?;
601 let value_offset = align_bit_offset(add_group_bits(
602 length_offset,
603 params.num_groups,
604 params.scaled_group_length_bits as usize,
605 )?)?;
606
607 Ok(Self {
608 reference_offset,
609 width_offset,
610 length_offset,
611 value_offset,
612 })
613 }
614}
615
616fn add_group_bits(start_bit_offset: usize, count: usize, bits_per_group: usize) -> Result<usize> {
617 count
618 .checked_mul(bits_per_group)
619 .and_then(|total_bits| start_bit_offset.checked_add(total_bits))
620 .ok_or_else(|| Error::Other("bit offset overflow".into()))
621}
622
623fn align_bit_offset(bit_offset: usize) -> Result<usize> {
624 let remainder = bit_offset % 8;
625 if remainder == 0 {
626 Ok(bit_offset)
627 } else {
628 bit_offset
629 .checked_add(8 - remainder)
630 .ok_or_else(|| Error::Other("bit offset overflow".into()))
631 }
632}
633
634struct OutputCursor<'a, T> {
635 output: &'a mut [T],
636 bitmap: Option<&'a [u8]>,
637 next_index: usize,
638 values_written: usize,
639}
640
641impl<'a, T: DecodeSample> OutputCursor<'a, T> {
642 fn new(output: &'a mut [T], bitmap: Option<&'a [u8]>) -> Self {
643 Self {
644 output,
645 bitmap,
646 next_index: 0,
647 values_written: 0,
648 }
649 }
650
651 fn push_present(&mut self, value: T) -> Result<()> {
652 match self.bitmap {
653 Some(bitmap) => {
654 while self.next_index < self.output.len() {
655 if bitmap_bit(bitmap, self.next_index)? {
656 self.output[self.next_index] = value;
657 self.next_index += 1;
658 self.values_written += 1;
659 return Ok(());
660 }
661
662 self.output[self.next_index] = T::nan();
663 self.next_index += 1;
664 }
665
666 let expected = count_bitmap_present_points(bitmap, self.output.len())?;
667 Err(Error::DataLengthMismatch {
668 expected,
669 actual: self.values_written + 1,
670 })
671 }
672 None => {
673 if self.next_index >= self.output.len() {
674 return Err(Error::DataLengthMismatch {
675 expected: self.output.len(),
676 actual: self.next_index + 1,
677 });
678 }
679
680 self.output[self.next_index] = value;
681 self.next_index += 1;
682 self.values_written += 1;
683 Ok(())
684 }
685 }
686 }
687
688 fn finish(mut self) -> Result<()> {
689 if let Some(bitmap) = self.bitmap {
690 while self.next_index < self.output.len() {
691 if bitmap_bit(bitmap, self.next_index)? {
692 return Err(Error::DataLengthMismatch {
693 expected: count_bitmap_present_points(bitmap, self.output.len())?,
694 actual: self.values_written,
695 });
696 }
697 self.output[self.next_index] = T::nan();
698 self.next_index += 1;
699 }
700 }
701
702 if self.next_index != self.output.len() {
703 return Err(Error::DataLengthMismatch {
704 expected: self.output.len(),
705 actual: self.next_index,
706 });
707 }
708
709 Ok(())
710 }
711 fn values_written(&self) -> usize {
712 self.values_written
713 }
714}
715
716#[derive(Debug, Clone)]
717struct SpatialDescriptors {
718 order: u8,
719 first_value: i64,
720 second_value: Option<i64>,
721 overall_minimum: i64,
722}
723
724#[derive(Debug, Clone)]
725struct SpatialRestoreState {
726 descriptors: SpatialDescriptors,
727 previous: Option<i64>,
728 previous_difference: Option<i64>,
729 non_missing_seen: usize,
730}
731
732impl SpatialRestoreState {
733 fn new(descriptors: SpatialDescriptors) -> Self {
734 Self {
735 descriptors,
736 previous: None,
737 previous_difference: None,
738 non_missing_seen: 0,
739 }
740 }
741
742 fn restore(&mut self, value: Option<i64>) -> Result<Option<i64>> {
743 let Some(value) = value else {
744 return Ok(None);
745 };
746
747 let restored = match self.descriptors.order {
748 1 => self.restore_first_order(value)?,
749 2 => self.restore_second_order(value)?,
750 other => return Err(Error::UnsupportedSpatialDifferencingOrder(other)),
751 };
752
753 self.previous = Some(restored);
754 self.non_missing_seen += 1;
755 Ok(Some(restored))
756 }
757
758 fn finish(self) -> Result<()> {
759 let expected = match self.descriptors.order {
760 1 => 1,
761 2 => 2,
762 other => return Err(Error::UnsupportedSpatialDifferencingOrder(other)),
763 };
764 if self.non_missing_seen < expected {
765 return Err(Error::DataLengthMismatch {
766 expected,
767 actual: self.non_missing_seen,
768 });
769 }
770 Ok(())
771 }
772
773 fn restore_first_order(&mut self, value: i64) -> Result<i64> {
774 if self.non_missing_seen == 0 {
775 return Ok(self.descriptors.first_value);
776 }
777
778 let delta = value
779 .checked_add(self.descriptors.overall_minimum)
780 .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
781 self.previous
782 .and_then(|previous| previous.checked_add(delta))
783 .ok_or_else(|| Error::Other("spatial differencing overflow".into()))
784 }
785
786 fn restore_second_order(&mut self, value: i64) -> Result<i64> {
787 match self.non_missing_seen {
788 0 => Ok(self.descriptors.first_value),
789 1 => {
790 let second_value = self.descriptors.second_value.ok_or(Error::InvalidSection {
791 section: 5,
792 reason: "missing second-order spatial differencing descriptors".into(),
793 })?;
794 self.previous_difference = second_value.checked_sub(self.descriptors.first_value);
795 self.previous_difference
796 .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
797 Ok(second_value)
798 }
799 _ => {
800 let second_difference = value
801 .checked_add(self.descriptors.overall_minimum)
802 .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
803 let difference = self
804 .previous_difference
805 .and_then(|previous_difference| {
806 previous_difference.checked_add(second_difference)
807 })
808 .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
809 let next = self
810 .previous
811 .and_then(|previous| previous.checked_add(difference))
812 .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
813 self.previous_difference = Some(difference);
814 Ok(next)
815 }
816 }
817 }
818}
819
820#[derive(Debug, Clone, Copy, PartialEq, Eq)]
821enum MissingKind {
822 Primary,
823 Secondary,
824}
825
826#[cfg(test)]
827mod tests {
828 use super::{
829 bitmap_payload, count_bitmap_present_points, decode_field, unpack_complex, unpack_simple,
830 ComplexPackingParams, DataRepresentation, SimplePackingParams, SpatialDifferencingParams,
831 };
832 use crate::error::Error;
833
834 #[test]
835 fn unpack_simple_constant() {
836 let params = SimplePackingParams {
837 encoded_values: 5,
838 reference_value: 42.0,
839 binary_scale: 0,
840 decimal_scale: 0,
841 bits_per_value: 0,
842 original_field_type: 0,
843 };
844 let values = unpack_simple(&[], ¶ms, 5).unwrap();
845 assert_eq!(values, vec![42.0; 5]);
846 }
847
848 #[test]
849 fn unpack_simple_basic() {
850 let params = SimplePackingParams {
851 encoded_values: 5,
852 reference_value: 0.0,
853 binary_scale: 0,
854 decimal_scale: 0,
855 bits_per_value: 8,
856 original_field_type: 0,
857 };
858 let values = unpack_simple(&[0, 1, 2, 3, 4], ¶ms, 5).unwrap();
859 assert_eq!(values, vec![0.0, 1.0, 2.0, 3.0, 4.0]);
860 }
861
862 #[test]
863 fn unpack_simple_applies_decimal_scale_to_reference_and_values() {
864 let params = SimplePackingParams {
865 encoded_values: 2,
866 reference_value: 10.0,
867 binary_scale: 0,
868 decimal_scale: 1,
869 bits_per_value: 8,
870 original_field_type: 0,
871 };
872
873 let values = unpack_simple(&[0, 20], ¶ms, 2).unwrap();
874 assert!((values[0] - 1.0).abs() < 1e-12);
875 assert!((values[1] - 3.0).abs() < 1e-12);
876 }
877
878 #[test]
879 fn decodes_bitmap_masked_field() {
880 let data_section = [0, 0, 0, 8, 7, 10, 20, 30];
881 let bitmap_section = [0, 0, 0, 7, 6, 0, 0b1011_0000];
882 let representation = DataRepresentation::SimplePacking(SimplePackingParams {
883 encoded_values: 3,
884 reference_value: 0.0,
885 binary_scale: 0,
886 decimal_scale: 0,
887 bits_per_value: 8,
888 original_field_type: 0,
889 });
890
891 let bitmap = bitmap_payload(&bitmap_section).unwrap();
892 let decoded = decode_field(&data_section, &representation, bitmap, 4).unwrap();
893 assert_eq!(decoded[0], 10.0);
894 assert!(decoded[1].is_nan());
895 assert_eq!(decoded[2], 20.0);
896 assert_eq!(decoded[3], 30.0);
897 }
898
899 #[test]
900 fn rejects_simple_packing_wider_than_u64() {
901 let params = SimplePackingParams {
902 encoded_values: 1,
903 reference_value: 0.0,
904 binary_scale: 0,
905 decimal_scale: 0,
906 bits_per_value: 65,
907 original_field_type: 0,
908 };
909 let err = unpack_simple(&[0; 9], ¶ms, 1).unwrap_err();
910 assert!(matches!(err, Error::UnsupportedPackingWidth(65)));
911 }
912
913 #[test]
914 fn rejects_encoded_value_count_mismatch_without_bitmap() {
915 let data_section = [0, 0, 0, 8, 7, 10, 20, 30];
916 let representation = DataRepresentation::SimplePacking(SimplePackingParams {
917 encoded_values: 3,
918 reference_value: 0.0,
919 binary_scale: 0,
920 decimal_scale: 0,
921 bits_per_value: 8,
922 original_field_type: 0,
923 });
924
925 let err = decode_field(&data_section, &representation, None, 4).unwrap_err();
926 assert!(matches!(
927 err,
928 Error::DataLengthMismatch {
929 expected: 4,
930 actual: 3,
931 }
932 ));
933 }
934
935 #[test]
936 fn rejects_bitmap_present_count_mismatch() {
937 let data_section = [0, 0, 0, 7, 7, 10, 20];
938 let bitmap_section = [0, 0, 0, 7, 6, 0, 0b1011_0000];
939 let representation = DataRepresentation::SimplePacking(SimplePackingParams {
940 encoded_values: 2,
941 reference_value: 0.0,
942 binary_scale: 0,
943 decimal_scale: 0,
944 bits_per_value: 8,
945 original_field_type: 0,
946 });
947
948 let bitmap = bitmap_payload(&bitmap_section).unwrap();
949 let err = decode_field(&data_section, &representation, bitmap, 4).unwrap_err();
950 assert!(matches!(
951 err,
952 Error::DataLengthMismatch {
953 expected: 3,
954 actual: 2,
955 }
956 ));
957 }
958
959 #[test]
960 fn counts_bitmap_present_points_with_partial_bytes() {
961 let present = count_bitmap_present_points(&[0b1011_1111], 3).unwrap();
962 assert_eq!(present, 2);
963 }
964
965 #[test]
966 fn unpacks_complex_packing_with_explicit_missing() {
967 let params = ComplexPackingParams {
968 encoded_values: 4,
969 reference_value: 0.0,
970 binary_scale: 0,
971 decimal_scale: 0,
972 group_reference_bits: 4,
973 original_field_type: 0,
974 group_splitting_method: 1,
975 missing_value_management: 1,
976 primary_missing_substitute: u32::MAX,
977 secondary_missing_substitute: u32::MAX,
978 num_groups: 2,
979 group_width_reference: 0,
980 group_width_bits: 2,
981 group_length_reference: 2,
982 group_length_increment: 1,
983 true_length_last_group: 2,
984 scaled_group_length_bits: 0,
985 spatial_differencing: None,
986 };
987
988 let values = unpack_complex(&[0x79, 0x90, 0x34], ¶ms).unwrap();
989 assert_eq!(values[0], 7.0);
990 assert!(values[1].is_nan());
991 assert_eq!(values[2], 9.0);
992 assert!(values[3].is_nan());
993 }
994
995 #[test]
996 fn unpacks_complex_packing_applies_decimal_scale_to_reference_and_values() {
997 let params = ComplexPackingParams {
998 encoded_values: 2,
999 reference_value: 10.0,
1000 binary_scale: 0,
1001 decimal_scale: 1,
1002 group_reference_bits: 4,
1003 original_field_type: 0,
1004 group_splitting_method: 1,
1005 missing_value_management: 0,
1006 primary_missing_substitute: u32::MAX,
1007 secondary_missing_substitute: u32::MAX,
1008 num_groups: 1,
1009 group_width_reference: 4,
1010 group_width_bits: 0,
1011 group_length_reference: 2,
1012 group_length_increment: 1,
1013 true_length_last_group: 2,
1014 scaled_group_length_bits: 0,
1015 spatial_differencing: None,
1016 };
1017
1018 let values = unpack_complex(&[0x10, 0x02], ¶ms).unwrap();
1019 assert!((values[0] - 1.1).abs() < 1e-12);
1020 assert!((values[1] - 1.3).abs() < 1e-12);
1021 }
1022
1023 #[test]
1024 fn unpacks_complex_packing_with_second_order_spatial_differencing() {
1025 let params = ComplexPackingParams {
1026 encoded_values: 4,
1027 reference_value: 0.0,
1028 binary_scale: 0,
1029 decimal_scale: 0,
1030 group_reference_bits: 1,
1031 original_field_type: 0,
1032 group_splitting_method: 1,
1033 missing_value_management: 0,
1034 primary_missing_substitute: u32::MAX,
1035 secondary_missing_substitute: u32::MAX,
1036 num_groups: 1,
1037 group_width_reference: 1,
1038 group_width_bits: 0,
1039 group_length_reference: 4,
1040 group_length_increment: 1,
1041 true_length_last_group: 4,
1042 scaled_group_length_bits: 0,
1043 spatial_differencing: Some(SpatialDifferencingParams {
1044 order: 2,
1045 descriptor_octets: 2,
1046 }),
1047 };
1048
1049 let values =
1050 unpack_complex(&[0x00, 0x0A, 0x00, 0x0D, 0x00, 0x03, 0x00, 0x10], ¶ms).unwrap();
1051 assert_eq!(values, vec![10.0, 13.0, 19.0, 29.0]);
1052 }
1053
1054 #[test]
1055 fn unpacks_complex_packing_with_spatial_differencing_and_missing_values() {
1056 let params = ComplexPackingParams {
1057 encoded_values: 4,
1058 reference_value: 0.0,
1059 binary_scale: 0,
1060 decimal_scale: 0,
1061 group_reference_bits: 1,
1062 original_field_type: 0,
1063 group_splitting_method: 1,
1064 missing_value_management: 1,
1065 primary_missing_substitute: u32::MAX,
1066 secondary_missing_substitute: u32::MAX,
1067 num_groups: 1,
1068 group_width_reference: 2,
1069 group_width_bits: 0,
1070 group_length_reference: 4,
1071 group_length_increment: 1,
1072 true_length_last_group: 4,
1073 scaled_group_length_bits: 0,
1074 spatial_differencing: Some(SpatialDifferencingParams {
1075 order: 1,
1076 descriptor_octets: 2,
1077 }),
1078 };
1079
1080 let values = unpack_complex(&[0x00, 0x0A, 0x00, 0x03, 0x00, 0x32], ¶ms).unwrap();
1081 assert_eq!(values[0], 10.0);
1082 assert!(values[1].is_nan());
1083 assert_eq!(values[2], 13.0);
1084 assert_eq!(values[3], 18.0);
1085 }
1086}