Skip to main content

grib_reader/
data.rs

1//! Data Section (Section 7) decoding.
2
3use crate::error::{Error, Result};
4use grib_core::bit::{read_bit, BitReader};
5pub use grib_core::data::{
6    ComplexPackingParams, DataRepresentation, SimplePackingParams, SpatialDifferencingParams,
7};
8
9/// Numeric target type for decoded field values.
10pub 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
35/// Decode Section 7 payload into field values, applying Section 6 bitmap when present.
36pub 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
57/// Decode Section 7 payload into a caller-provided buffer, applying Section 6
58/// bitmap when present.
59pub 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
152/// Parse bitmap presence from Section 6.
153pub 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(&section_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
200/// Unpack simple-packed values.
201pub 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(&[], &params, 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], &params, 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], &params, 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], &params, 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], &params).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], &params).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], &params).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], &params).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}