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