1use crate::error::{Error, Result};
4use crate::util::grib_i16;
5
6#[derive(Debug, Clone, PartialEq)]
8pub enum DataRepresentation {
9 SimplePacking(SimplePackingParams),
11 Unsupported(u16),
13}
14
15#[derive(Debug, Clone, PartialEq)]
17pub struct SimplePackingParams {
18 pub encoded_values: usize,
19 pub reference_value: f32,
20 pub binary_scale: i16,
21 pub decimal_scale: i16,
22 pub bits_per_value: u8,
23 pub original_field_type: u8,
24}
25
26impl DataRepresentation {
27 pub fn parse(section_bytes: &[u8]) -> Result<Self> {
28 if section_bytes.len() < 11 {
29 return Err(Error::InvalidSection {
30 section: 5,
31 reason: format!("expected at least 11 bytes, got {}", section_bytes.len()),
32 });
33 }
34 if section_bytes[4] != 5 {
35 return Err(Error::InvalidSection {
36 section: section_bytes[4],
37 reason: "not a data representation section".into(),
38 });
39 }
40
41 let template = u16::from_be_bytes(section_bytes[9..11].try_into().unwrap());
42 match template {
43 0 => parse_simple_packing(section_bytes),
44 _ => Ok(Self::Unsupported(template)),
45 }
46 }
47
48 pub fn encoded_values(&self) -> Option<usize> {
49 match self {
50 Self::SimplePacking(params) => Some(params.encoded_values),
51 Self::Unsupported(_) => None,
52 }
53 }
54}
55
56pub fn decode_field(
58 data_section: &[u8],
59 representation: &DataRepresentation,
60 bitmap_section: Option<&[u8]>,
61 num_grid_points: usize,
62) -> Result<Vec<f64>> {
63 if data_section.len() < 5 || data_section[4] != 7 {
64 return Err(Error::InvalidSection {
65 section: data_section.get(4).copied().unwrap_or(7),
66 reason: "not a data section".into(),
67 });
68 }
69
70 decode_payload(
71 &data_section[5..],
72 representation,
73 bitmap_section,
74 num_grid_points,
75 )
76}
77
78pub(crate) fn decode_payload(
79 payload: &[u8],
80 representation: &DataRepresentation,
81 bitmap_section: Option<&[u8]>,
82 num_grid_points: usize,
83) -> Result<Vec<f64>> {
84 match representation {
85 DataRepresentation::SimplePacking(params) => {
86 let unpacked = unpack_simple(payload, params, params.encoded_values)?;
87 match bitmap_section {
88 Some(bitmap) => apply_bitmap(bitmap, unpacked, num_grid_points),
89 None => {
90 if params.encoded_values != num_grid_points {
91 return Err(Error::DataLengthMismatch {
92 expected: num_grid_points,
93 actual: params.encoded_values,
94 });
95 }
96 Ok(unpacked)
97 }
98 }
99 }
100 DataRepresentation::Unsupported(template) => Err(Error::UnsupportedDataTemplate(*template)),
101 }
102}
103
104pub fn bitmap_payload(section_bytes: &[u8]) -> Result<Option<&[u8]>> {
106 if section_bytes.len() < 6 {
107 return Err(Error::InvalidSection {
108 section: 6,
109 reason: format!("expected at least 6 bytes, got {}", section_bytes.len()),
110 });
111 }
112 if section_bytes[4] != 6 {
113 return Err(Error::InvalidSection {
114 section: section_bytes[4],
115 reason: "not a bitmap section".into(),
116 });
117 }
118
119 match section_bytes[5] {
120 255 => Ok(None),
121 0 => Ok(Some(§ion_bytes[6..])),
122 indicator => Err(Error::UnsupportedBitmapIndicator(indicator)),
123 }
124}
125
126fn parse_simple_packing(data: &[u8]) -> Result<DataRepresentation> {
127 if data.len() < 21 {
128 return Err(Error::InvalidSection {
129 section: 5,
130 reason: format!("template 5.0 requires 21 bytes, got {}", data.len()),
131 });
132 }
133
134 let encoded_values = u32::from_be_bytes(data[5..9].try_into().unwrap()) as usize;
135 let reference_value = f32::from_be_bytes(data[11..15].try_into().unwrap());
136 let binary_scale = grib_i16(&data[15..17]).unwrap();
137 let decimal_scale = grib_i16(&data[17..19]).unwrap();
138 let bits_per_value = data[19];
139 let original_field_type = data[20];
140
141 Ok(DataRepresentation::SimplePacking(SimplePackingParams {
142 encoded_values,
143 reference_value,
144 binary_scale,
145 decimal_scale,
146 bits_per_value,
147 original_field_type,
148 }))
149}
150
151pub fn unpack_simple(
153 data_bytes: &[u8],
154 params: &SimplePackingParams,
155 num_values: usize,
156) -> Result<Vec<f64>> {
157 let bits = params.bits_per_value as usize;
158 if bits == 0 {
159 return Ok(vec![params.reference_value as f64; num_values]);
160 }
161 if bits > u64::BITS as usize {
162 return Err(Error::UnsupportedPackingWidth(params.bits_per_value));
163 }
164
165 let required_bits = bits
166 .checked_mul(num_values)
167 .ok_or_else(|| Error::Other("bit count overflow during unpacking".into()))?;
168 let required_bytes = required_bits.div_ceil(8);
169 if data_bytes.len() < required_bytes {
170 return Err(Error::Truncated {
171 offset: data_bytes.len() as u64,
172 });
173 }
174
175 let binary_factor = 2.0_f64.powi(params.binary_scale as i32);
176 let decimal_factor = 10.0_f64.powi(-(params.decimal_scale as i32));
177 let reference = params.reference_value as f64;
178 let mut reader = BitReader::new(data_bytes);
179 let mut values = Vec::with_capacity(num_values);
180
181 for _ in 0..num_values {
182 let packed = reader.read(bits)?;
183 values.push(reference + (packed as f64) * binary_factor * decimal_factor);
184 }
185
186 Ok(values)
187}
188
189fn apply_bitmap(
190 bitmap_payload: &[u8],
191 packed_values: Vec<f64>,
192 num_grid_points: usize,
193) -> Result<Vec<f64>> {
194 let mut decoded = Vec::with_capacity(num_grid_points);
195 let mut packed_iter = packed_values.into_iter();
196 let mut present_points = 0usize;
197
198 for bit_index in 0..num_grid_points {
199 if bitmap_bit(bitmap_payload, bit_index)? {
200 present_points += 1;
201 decoded.push(packed_iter.next().ok_or(Error::MissingBitmap)?);
202 } else {
203 decoded.push(f64::NAN);
204 }
205 }
206
207 let extra_values = packed_iter.count();
208 if extra_values > 0 {
209 return Err(Error::DataLengthMismatch {
210 expected: present_points,
211 actual: present_points + extra_values,
212 });
213 }
214
215 Ok(decoded)
216}
217
218fn bitmap_bit(bitmap_payload: &[u8], index: usize) -> Result<bool> {
219 let byte_index = index / 8;
220 let bit_index = index % 8;
221 let byte = bitmap_payload
222 .get(byte_index)
223 .copied()
224 .ok_or(Error::MissingBitmap)?;
225 Ok(((byte >> (7 - bit_index)) & 1) != 0)
226}
227
228struct BitReader<'a> {
229 data: &'a [u8],
230 bit_offset: usize,
231}
232
233impl<'a> BitReader<'a> {
234 fn new(data: &'a [u8]) -> Self {
235 Self {
236 data,
237 bit_offset: 0,
238 }
239 }
240
241 fn read(&mut self, bit_count: usize) -> Result<u64> {
242 let mut remaining = bit_count;
243 let mut value = 0u64;
244
245 while remaining > 0 {
246 let byte_index = self.bit_offset / 8;
247 let bit_index = self.bit_offset % 8;
248 let byte = *self.data.get(byte_index).ok_or(Error::Truncated {
249 offset: byte_index as u64,
250 })?;
251 let available = 8 - bit_index;
252 let take = remaining.min(available);
253 let mask = ((1u16 << take) - 1) as u8;
254 let shift = available - take;
255 let bits = (byte >> shift) & mask;
256
257 value = (value << take) | bits as u64;
258 self.bit_offset += take;
259 remaining -= take;
260 }
261
262 Ok(value)
263 }
264}
265
266#[cfg(test)]
267mod tests {
268 use super::{
269 bitmap_payload, decode_field, unpack_simple, DataRepresentation, SimplePackingParams,
270 };
271 use crate::error::Error;
272
273 #[test]
274 fn unpack_simple_constant() {
275 let params = SimplePackingParams {
276 encoded_values: 5,
277 reference_value: 42.0,
278 binary_scale: 0,
279 decimal_scale: 0,
280 bits_per_value: 0,
281 original_field_type: 0,
282 };
283 let values = unpack_simple(&[], ¶ms, 5).unwrap();
284 assert_eq!(values, vec![42.0; 5]);
285 }
286
287 #[test]
288 fn unpack_simple_basic() {
289 let params = SimplePackingParams {
290 encoded_values: 5,
291 reference_value: 0.0,
292 binary_scale: 0,
293 decimal_scale: 0,
294 bits_per_value: 8,
295 original_field_type: 0,
296 };
297 let values = unpack_simple(&[0, 1, 2, 3, 4], ¶ms, 5).unwrap();
298 assert_eq!(values, vec![0.0, 1.0, 2.0, 3.0, 4.0]);
299 }
300
301 #[test]
302 fn decodes_bitmap_masked_field() {
303 let data_section = [0, 0, 0, 8, 7, 10, 20, 30];
304 let bitmap_section = [0, 0, 0, 7, 6, 0, 0b1011_0000];
305 let representation = DataRepresentation::SimplePacking(SimplePackingParams {
306 encoded_values: 3,
307 reference_value: 0.0,
308 binary_scale: 0,
309 decimal_scale: 0,
310 bits_per_value: 8,
311 original_field_type: 0,
312 });
313
314 let bitmap = bitmap_payload(&bitmap_section).unwrap();
315 let decoded = decode_field(&data_section, &representation, bitmap, 4).unwrap();
316 assert_eq!(decoded[0], 10.0);
317 assert!(decoded[1].is_nan());
318 assert_eq!(decoded[2], 20.0);
319 assert_eq!(decoded[3], 30.0);
320 }
321
322 #[test]
323 fn rejects_simple_packing_wider_than_u64() {
324 let params = SimplePackingParams {
325 encoded_values: 1,
326 reference_value: 0.0,
327 binary_scale: 0,
328 decimal_scale: 0,
329 bits_per_value: 65,
330 original_field_type: 0,
331 };
332 let err = unpack_simple(&[0; 9], ¶ms, 1).unwrap_err();
333 assert!(matches!(err, Error::UnsupportedPackingWidth(65)));
334 }
335
336 #[test]
337 fn rejects_encoded_value_count_mismatch_without_bitmap() {
338 let data_section = [0, 0, 0, 8, 7, 10, 20, 30];
339 let representation = DataRepresentation::SimplePacking(SimplePackingParams {
340 encoded_values: 3,
341 reference_value: 0.0,
342 binary_scale: 0,
343 decimal_scale: 0,
344 bits_per_value: 8,
345 original_field_type: 0,
346 });
347
348 let err = decode_field(&data_section, &representation, None, 4).unwrap_err();
349 assert!(matches!(
350 err,
351 Error::DataLengthMismatch {
352 expected: 4,
353 actual: 3,
354 }
355 ));
356 }
357}