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