1use grib_template_helpers::WriteToBuffer;
2
3use crate::{
4 WriteGrib2DataSections,
5 def::grib2::template::param_set::SimplePacking,
6 encoder::{Encode, bitmap::Bitmap, helpers::BitsRequired, writer},
7};
8
9#[derive(Debug, PartialEq, Eq, Clone)]
13pub enum SimplePackingStrategy {
14 Decimal(i16),
19}
20
21pub(crate) struct Encoder<'a> {
22 data: &'a [f64],
23 strategy: SimplePackingStrategy,
24}
25
26impl<'a> Encoder<'a> {
27 pub(crate) fn new(data: &'a [f64], strategy: SimplePackingStrategy) -> Self {
28 Self { data, strategy }
29 }
30}
31
32impl<'a> Encode for Encoder<'a> {
33 type Output = Encoded;
34
35 fn encode(&self) -> Self::Output {
36 match self.strategy {
37 SimplePackingStrategy::Decimal(dec) => {
38 let (params, scaled, bitmap) = determine_simple_packing_params(self.data, dec);
39 let coded = if params.num_bits == 0 {
40 CodedValues::Unique(self.data.len())
41 } else {
42 let exp = 2_f64.powf(params.exp as f64);
43 let coded = scaled
44 .iter()
45 .map(|value| ((value - params.ref_val as f64) / exp).round() as u32)
46 .collect::<Vec<_>>();
47 CodedValues::NonUnique(coded)
48 };
49 Encoded::new(params, coded, bitmap)
50 }
51 }
52 }
53}
54
55#[derive(Debug)]
56pub(crate) struct Encoded {
57 params: SimplePacking,
58 coded: CodedValues,
59 bitmap: Bitmap,
60}
61
62impl Encoded {
63 fn new(params: SimplePacking, coded: CodedValues, bitmap: Bitmap) -> Self {
64 Self {
65 params,
66 coded,
67 bitmap,
68 }
69 }
70
71 pub(crate) fn params(&self) -> &SimplePacking {
72 &self.params
73 }
74}
75
76impl WriteGrib2DataSections for Encoded {
77 fn section5_len(&self) -> usize {
78 21
79 }
80
81 fn write_section5(&self, buf: &mut [u8]) -> Result<usize, &'static str> {
82 let len = self.section5_len();
83 if buf.len() < len {
84 return Err("destination buffer is too small");
85 }
86
87 let mut pos = 0;
88 pos += (len as u32).write_to_buffer(&mut buf[pos..])?; pos += 5_u8.write_to_buffer(&mut buf[pos..])?; pos += (self.coded.num_values() as u32).write_to_buffer(&mut buf[pos..])?; pos += 0_u16.write_to_buffer(&mut buf[pos..])?; pos += self.params.write_to_buffer(&mut buf[pos..])?;
93 pos += 0_u8.write_to_buffer(&mut buf[pos..])?; Ok(pos)
96 }
97
98 fn section6_len(&self) -> usize {
99 let bitmap_size = if self.bitmap.has_nan() {
100 self.bitmap.num_bytes_required()
101 } else {
102 0
103 };
104 6 + bitmap_size
105 }
106
107 fn write_section6(&self, buf: &mut [u8]) -> Result<usize, &'static str> {
108 let len = self.section6_len();
109 if buf.len() < len {
110 return Err("destination buffer is too small");
111 }
112
113 let mut pos = 0;
114 pos += (len as u32).write_to_buffer(&mut buf[pos..])?;
115 pos += 6_u8.write_to_buffer(&mut buf[pos..])?;
116 if self.bitmap.has_nan() {
117 pos += 0_u8.write_to_buffer(&mut buf[pos..])?;
118 pos += self.bitmap.write_to_buffer(&mut buf[pos..])?;
119 } else {
120 pos += 255_u8.write_to_buffer(&mut buf[pos..])?;
121 }
122
123 Ok(pos)
124 }
125
126 fn section7_len(&self) -> usize {
127 let len = match &self.coded {
128 CodedValues::NonUnique(vec) => {
129 let nbitwise = writer::NBitwise::new(&vec, self.params.num_bits as usize);
130 nbitwise.num_bytes_required()
131 }
132 CodedValues::Unique(_) => 0,
133 };
134 5 + len
135 }
136
137 fn write_section7(&self, buf: &mut [u8]) -> Result<usize, &'static str> {
138 let len = self.section7_len();
139 if buf.len() < len {
140 return Err("destination buffer is too small");
141 }
142
143 let mut pos = 0;
144 pos += (len as u32).write_to_buffer(&mut buf[pos..])?;
145 pos += 7_u8.write_to_buffer(&mut buf[pos..])?;
146 match &self.coded {
147 CodedValues::NonUnique(vec) => {
148 let nbitwise = writer::NBitwise::new(&vec, self.params.num_bits as usize);
149 pos += nbitwise.write_to_buffer(&mut buf[pos..])?;
150 }
151 CodedValues::Unique(_) => {}
152 }
153
154 Ok(pos)
155 }
156}
157
158pub(crate) fn determine_simple_packing_params(
159 values: &[f64],
160 dec: i16,
161) -> (SimplePacking, Vec<f64>, Bitmap) {
162 let mut min = f64::MAX;
163 let mut max = f64::MIN;
164 let mut bitmap = Bitmap::for_values(values);
165 let scaled = values
166 .iter()
167 .filter_map(|value| {
168 if value.is_nan() {
169 bitmap.push(false);
170 None
171 } else {
172 bitmap.push(true);
173 let scaled = value * 10_f64.powf(dec as f64);
174 (min, max) = (scaled.min(min), scaled.max(max));
175 Some(scaled)
176 }
177 })
178 .collect::<Vec<_>>();
179 let ref_val = min as f32;
180 if min == max {
181 let params = SimplePacking {
182 ref_val,
183 exp: 0,
184 dec,
185 num_bits: 0,
186 };
187 (params, Vec::new(), bitmap)
188 } else {
189 let range = max - min;
190 let exp = 0;
191 let num_bits = range.bits_required();
192 let params = SimplePacking {
194 ref_val,
195 exp,
196 dec,
197 num_bits,
198 };
199 (params, scaled, bitmap)
200 }
201}
202
203#[derive(Debug)]
204enum CodedValues {
205 NonUnique(Vec<u32>),
206 Unique(usize),
207}
208
209impl CodedValues {
210 pub(crate) fn num_values(&self) -> usize {
211 match self {
212 Self::NonUnique(vec) => vec.len(),
213 Self::Unique(size) => *size,
214 }
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221
222 macro_rules! test_decimal_strategy {
223 ($((
224 $name:ident,
225 $input:expr,
226 $decimal:expr,
227 $expected_params:expr,
228 ),)*) => ($(
229 #[test]
230 fn $name() {
231 let values = $input;
232 let encoder = Encoder::new(&values, SimplePackingStrategy::Decimal($decimal));
233 let encoded = encoder.encode();
234 let actual_params = encoded.params();
235 let expected_params = $expected_params;
236 assert_eq!(actual_params, &expected_params);
237 let actual_num_values = encoded.coded.num_values();
238 assert_eq!(actual_num_values, values.len());
239 }
240 )*);
241 }
242
243 test_decimal_strategy! {
244 (
245 decimal_strategy_with_decimal_0,
246 (2..11).map(|val| val as f64).collect::<Vec<_>>(),
247 0,
248 SimplePacking {
249 ref_val: 2.,
250 exp: 0,
251 dec: 0,
252 num_bits: 4,
253 },
254 ),
255 (
256 decimal_strategy_with_decimal_1,
257 (2..11).map(|val| val as f64).collect::<Vec<_>>(),
258 1,
259 SimplePacking {
260 ref_val: 20.,
261 exp: 0,
262 dec: 1,
263 num_bits: 7,
264 },
265 ),
266 (
267 decimal_strategy_with_decimal_0_for_unique_values,
268 vec![10.0_f64; 256],
269 0,
270 SimplePacking {
271 ref_val: 10.0,
272 exp: 0,
273 dec: 0,
274 num_bits: 0,
275 },
276 ),
277 }
278
279 macro_rules! grib2_coded_values_roundtrip_tests {
280 ($(($name:ident, $input:expr, $decimal:expr),)*) => ($(
281 #[test]
282 fn $name() -> Result<(), Box<dyn std::error::Error>> {
283 let values = $input;
284 let encoder = Encoder::new(&values, SimplePackingStrategy::Decimal($decimal));
285 let encoded = encoder.encode();
286 let mut sect5 = vec![0; encoded.section5_len()];
287 let pos = encoded.write_section5(&mut sect5)?;
288 assert_eq!(pos, sect5.len());
289 let mut sect6 = vec![0; encoded.section6_len()];
290 let pos = encoded.write_section6(&mut sect6)?;
291 assert_eq!(pos, sect6.len());
292 let mut sect7 = vec![0; encoded.section7_len()];
293 let pos = encoded.write_section7(&mut sect7)?;
294 assert_eq!(pos, sect7.len());
295 let decoder = crate::Grib2SubmessageDecoder::new(values.len(), sect5, sect6, sect7)?;
296 let actual = decoder.dispatch()?.collect::<Vec<_>>();
297 let expected = values.iter().map(|val| *val as f32).collect::<Vec<_>>();
298 assert_eq!(actual.len(), expected.len());
299 actual
300 .iter()
301 .zip(expected.iter())
302 .all(|(a, b)| (a.is_nan() && b.is_nan()) || (a == b));
303 Ok(())
304 }
305 )*);
306 }
307
308 grib2_coded_values_roundtrip_tests! {
309 (
310 grib2_coded_values_roundtrip_test_with_decimal_0_and_nonunique_values,
311 (2..11).map(|val| val as f64).collect::<Vec<_>>(),
312 0
313 ),
314 (
315 grib2_coded_values_roundtrip_test_with_decimal_0_and_unique_values,
316 vec![10.0_f64; 256],
317 0
318 ),
319 (
320 grib2_coded_values_roundtrip_test_with_data_containing_nan_values,
321 [f64::NAN; 32]
322 .into_iter()
323 .chain([1., 2., 3.].into_iter())
324 .chain([f64::NAN; 32].into_iter())
325 .chain([4., 5., 6., 7.].into_iter())
326 .chain([f64::NAN; 32].into_iter())
327 .chain([8., 9., 10., 11.].into_iter())
328 .collect::<Vec<_>>(),
329 0
330 ),
331 }
332}