Skip to main content

grib_reader/
data.rs

1//! Data Representation Section (Section 5) and Data Section (Section 7) decoding.
2
3use crate::error::{Error, Result};
4use crate::util::grib_i16;
5
6/// Data representation template number and parameters.
7#[derive(Debug, Clone, PartialEq)]
8pub enum DataRepresentation {
9    /// Template 5.0: Simple packing.
10    SimplePacking(SimplePackingParams),
11    /// Template 5.2/5.3: Complex packing with optional spatial differencing.
12    ComplexPacking(ComplexPackingParams),
13    /// Unsupported template.
14    Unsupported(u16),
15}
16
17/// Parameters for simple packing (Template 5.0).
18#[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/// Parameters for complex packing (Templates 5.2 and 5.3).
29#[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/// Parameters specific to template 5.3 spatial differencing.
52#[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
91/// Decode Section 7 payload into field values, applying Section 6 bitmap when present.
92pub 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
154/// Parse bitmap presence from Section 6.
155pub 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(&section_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
266/// Unpack simple-packed values.
267pub 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(&[], &params, 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], &params, 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], &params, 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], &params).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], &params).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], &params).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}