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