1use super::missing::DecodedValue::{self, Normal};
2use crate::{
3 decoder::{param::SpatialDifferencingParam, DecodeError},
4 helpers::grib_int_from_bytes,
5};
6
7pub(crate) struct SpatialDifferencingExtraDescriptors<'a> {
8 slice: &'a [u8],
9 num_octets: usize,
10}
11
12impl<'a> SpatialDifferencingExtraDescriptors<'a> {
13 pub(crate) fn new(
14 param: &SpatialDifferencingParam,
15 parent_slice: &'a [u8],
16 ) -> Result<Self, DecodeError> {
17 let SpatialDifferencingParam {
18 order,
19 extra_desc_num_octets,
20 } = param;
21 if *extra_desc_num_octets == 0 || *extra_desc_num_octets > 4 {
22 return Err(DecodeError::from(
23 format!("unexpected value for \"number of octets required in the data section to specify extra descriptors needed for spatial differencing\": {extra_desc_num_octets}")
24 ));
25 }
26 let num_octets = usize::from(*extra_desc_num_octets);
27 let byte_length = usize::from(order + 1) * num_octets;
28
29 Ok(Self {
30 slice: &parent_slice[..byte_length],
31 num_octets,
32 })
33 }
34
35 pub(crate) fn len(&self) -> usize {
37 self.slice.len()
38 }
39
40 pub(crate) fn minimum(&self) -> i32 {
42 let slice = &self.slice[self.first_value_end_pos()..];
43 grib_int_from_bytes(slice)
44 }
45
46 pub(crate) fn first_values(&self) -> FirstValues<'_, 'a> {
47 FirstValues::new(self)
48 }
49
50 fn first_value_end_pos(&self) -> usize {
51 self.len() - self.num_octets
52 }
53}
54
55pub(crate) struct FirstValues<'s, 'a> {
56 spdiff_info: &'s SpatialDifferencingExtraDescriptors<'a>,
57 pos: usize,
58}
59
60impl<'s, 'a> FirstValues<'s, 'a> {
61 pub(crate) fn new(spdiff_info: &'s SpatialDifferencingExtraDescriptors<'a>) -> Self {
62 Self {
63 spdiff_info,
64 pos: 0,
65 }
66 }
67}
68
69impl Iterator for FirstValues<'_, '_> {
70 type Item = i32;
71
72 fn next(&mut self) -> Option<Self::Item> {
73 if self.pos >= self.spdiff_info.first_value_end_pos() {
74 return None;
75 }
76
77 let num_octets = self.spdiff_info.num_octets;
78 let slice = &self.spdiff_info.slice[self.pos..self.pos + num_octets];
79 let val = grib_int_from_bytes(slice);
80 self.pos += num_octets;
81 Some(val)
82 }
83}
84
85pub(crate) enum SpatialDifferencingDecodeIterator<I, J> {
86 FirstOrder(FirstOrderSpatialDifferencingDecodeIterator<I, J>),
87 SecondOrder(SecondOrderSpatialDifferencingDecodeIterator<I, J>),
88}
89
90impl<I, J> Iterator for SpatialDifferencingDecodeIterator<I, J>
91where
92 I: Iterator<Item = DecodedValue<i32>>,
93 J: Iterator<Item = i32>,
94{
95 type Item = DecodedValue<i32>;
96
97 fn next(&mut self) -> Option<Self::Item> {
98 match self {
99 SpatialDifferencingDecodeIterator::FirstOrder(iter) => iter.next(),
100 SpatialDifferencingDecodeIterator::SecondOrder(iter) => iter.next(),
101 }
102 }
103}
104
105pub(crate) struct FirstOrderSpatialDifferencingDecodeIterator<I, J> {
106 iter: I,
107 first_values: J,
108 count: u32,
109 prev: i32,
110}
111
112impl<I, J> FirstOrderSpatialDifferencingDecodeIterator<I, J> {
113 pub(crate) fn new(iter: I, first_values: J) -> Self {
114 Self {
115 iter,
116 first_values,
117 count: 0,
118 prev: 0,
119 }
120 }
121}
122
123impl<I, J> Iterator for FirstOrderSpatialDifferencingDecodeIterator<I, J>
124where
125 I: Iterator<Item = DecodedValue<i32>>,
126 J: Iterator<Item = i32>,
127{
128 type Item = DecodedValue<i32>;
129
130 fn next(&mut self) -> Option<Self::Item> {
131 match self.iter.next() {
132 None => None,
133 Some(Normal(v)) => match self.count {
134 0 => {
135 self.prev = self.first_values.next().unwrap();
136 self.count += 1;
137 Some(Normal(self.prev))
138 }
139 _ => {
140 let v = v + self.prev;
141 self.prev = v;
142 Some(Normal(v))
143 }
144 },
145 Some(missing) => Some(missing),
146 }
147 }
148}
149
150pub(crate) struct SecondOrderSpatialDifferencingDecodeIterator<I, J> {
151 iter: I,
152 first_values: J,
153 count: u32,
154 prev1: i32,
155 prev2: i32,
156}
157
158impl<I, J> SecondOrderSpatialDifferencingDecodeIterator<I, J> {
159 pub(crate) fn new(iter: I, first_values: J) -> Self {
160 Self {
161 iter,
162 first_values,
163 count: 0,
164 prev1: 0,
165 prev2: 0,
166 }
167 }
168}
169
170impl<I, J> Iterator for SecondOrderSpatialDifferencingDecodeIterator<I, J>
171where
172 I: Iterator<Item = DecodedValue<i32>>,
173 J: Iterator<Item = i32>,
174{
175 type Item = DecodedValue<i32>;
176
177 fn next(&mut self) -> Option<Self::Item> {
178 match self.iter.next() {
179 None => None,
180 Some(Normal(v)) => match self.count {
181 0 => {
182 self.prev2 = self.first_values.next().unwrap();
183 self.count += 1;
184 Some(Normal(self.prev2))
185 }
186 1 => {
187 self.prev1 = self.first_values.next().unwrap();
188 self.count += 1;
189 Some(Normal(self.prev1))
190 }
191 _ => {
192 let v = v + 2 * self.prev1 - self.prev2;
193 self.prev2 = self.prev1;
194 self.prev1 = v;
195 Some(Normal(v))
196 }
197 },
198 Some(missing) => Some(missing),
199 }
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::{
206 super::missing::DecodedValue::{Missing1, Missing2},
207 *,
208 };
209
210 macro_rules! test_spdiff_minimum_value {
211 ($(($name:ident, $num_octets:expr, $expected:expr),)*) => ($(
212 #[test]
213 fn $name() {
214 let spdiff_param = SpatialDifferencingParam {
215 order: 2,
216 extra_desc_num_octets: $num_octets,
217 };
218 let octets = (0x00..0x10).collect::<Vec<_>>();
219 let spdiff_params =
220 SpatialDifferencingExtraDescriptors::new(&spdiff_param, &octets).unwrap();
221 let actual = spdiff_params.minimum();
222 assert_eq!(actual, $expected);
223 }
224 )*);
225 }
226
227 test_spdiff_minimum_value! {
228 (spdiff_minimum_value_when_num_octets_is_1, 1, 0x02),
229 (spdiff_minimum_value_when_num_octets_is_2, 2, 0x04_05),
230 (spdiff_minimum_value_when_num_octets_is_3, 3, 0x06_07_08),
231 (spdiff_minimum_value_when_num_octets_is_4, 4, 0x08_09_0a_0b),
232 }
233
234 macro_rules! test_spdiff_first_values {
235 ($(($name:ident, $num_octets:expr, $expected:expr),)*) => ($(
236 #[test]
237 fn $name() {
238 let spdiff_param = SpatialDifferencingParam {
239 order: 2,
240 extra_desc_num_octets: $num_octets,
241 };
242 let octets = (0x00..0x10).collect::<Vec<_>>();
243 let spdiff_params =
244 SpatialDifferencingExtraDescriptors::new(&spdiff_param, &octets).unwrap();
245 let actual = spdiff_params.first_values().collect::<Vec<_>>();
246 assert_eq!(actual, $expected);
247 }
248 )*);
249 }
250
251 test_spdiff_first_values! {
252 (spdiff_first_values_when_num_octets_is_1, 1, vec![0x00, 0x01]),
253 (spdiff_first_values_when_num_octets_is_2, 2, vec![0x00_01, 0x02_03]),
254 (spdiff_first_values_when_num_octets_is_3, 3, vec![0x00_01_02, 0x03_04_05]),
255 (spdiff_first_values_when_num_octets_is_4, 4, vec![0x00_01_02_03, 0x04_05_06_07]),
256 }
257
258 macro_rules! test_first_order_spatial_differencing_decoding {
259 ($(($name:ident, $input:expr, $expected:expr),)*) => ($(
260 #[test]
261 fn $name() {
262 let input = $input
263 .into_iter();
264 let first_values = vec![100].into_iter();
265 let iter = FirstOrderSpatialDifferencingDecodeIterator::new(input, first_values);
266 assert_eq!(
267 iter.collect::<Vec<_>>(),
268 $expected
269 );
270 }
271 )*);
272 }
273
274 test_first_order_spatial_differencing_decoding! {
275 (
276 first_order_spatial_differencing_decoding_consisting_of_normal_values,
277 (0_u32..10).map(|n| Normal(n as i32 * (-1_i32).pow(n))),
278 vec![
279 Normal(100),
280 Normal(99),
281 Normal(101),
282 Normal(98),
283 Normal(102),
284 Normal(97),
285 Normal(103),
286 Normal(96),
287 Normal(104),
288 Normal(95),
289 ]
290 ),
291 (
292 first_order_spatial_differencing_decoding_with_missing_values_in_first_values,
293 vec![
294 Missing1,
295 Normal(0),
296 Normal(-1),
297 Normal(2),
298 Normal(-3),
299 Normal(4),
300 Normal(-5),
301 Normal(6),
302 Normal(-7),
303 Normal(8),
304 ],
305 vec![
306 Missing1,
307 Normal(100),
308 Normal(99),
309 Normal(101),
310 Normal(98),
311 Normal(102),
312 Normal(97),
313 Normal(103),
314 Normal(96),
315 Normal(104),
316 ]
317 ),
318 (
319 first_order_spatial_differencing_decoding_with_missing_values_in_non_first_values,
320 vec![
321 Normal(0),
322 Normal(-1),
323 Missing1,
324 Normal(2),
325 Normal(-3),
326 Normal(4),
327 Missing2,
328 Normal(-5),
329 Normal(6),
330 Normal(-7),
331 ],
332 vec![
333 Normal(100),
334 Normal(99),
335 Missing1,
336 Normal(101),
337 Normal(98),
338 Normal(102),
339 Missing2,
340 Normal(97),
341 Normal(103),
342 Normal(96),
343 ]
344 ),
345 }
346
347 macro_rules! test_second_order_spatial_differencing_decoding {
348 ($(($name:ident, $input:expr, $expected:expr),)*) => ($(
349 #[test]
350 fn $name() {
351 let input = $input
352 .into_iter();
353 let first_values = vec![100, 99].into_iter();
354 let iter = SecondOrderSpatialDifferencingDecodeIterator::new(input, first_values);
355 assert_eq!(
356 iter.collect::<Vec<_>>(),
357 $expected
358 );
359 }
360 )*);
361 }
362
363 test_second_order_spatial_differencing_decoding! {
364 (
365 second_order_spatial_differencing_decoding_consisting_of_normal_values,
366 (0_u32..10).map(|n| Normal(n as i32 * (-1_i32).pow(n))),
367 vec![
368 Normal(100),
369 Normal(99),
370 Normal(100),
371 Normal(98),
372 Normal(100),
373 Normal(97),
374 Normal(100),
375 Normal(96),
376 Normal(100),
377 Normal(95),
378 ]
379 ),
380 (
381 second_order_spatial_differencing_decoding_with_missing_values_in_first_values,
382 vec![
383 Missing1,
384 Missing2,
385 Normal(0),
386 Normal(-1),
387 Normal(2),
388 Normal(-3),
389 Normal(4),
390 Normal(-5),
391 Normal(6),
392 Normal(-7),
393 ],
394 vec![
395 Missing1,
396 Missing2,
397 Normal(100),
398 Normal(99),
399 Normal(100),
400 Normal(98),
401 Normal(100),
402 Normal(97),
403 Normal(100),
404 Normal(96),
405 ]
406 ),
407 (
408 second_order_spatial_differencing_decoding_with_missing_values_in_non_first_values,
409 vec![
410 Normal(0),
411 Normal(-1),
412 Missing1,
413 Normal(2),
414 Normal(-3),
415 Normal(4),
416 Missing2,
417 Normal(-5),
418 Normal(6),
419 Normal(-7),
420 ],
421 vec![
422 Normal(100),
423 Normal(99),
424 Missing1,
425 Normal(100),
426 Normal(98),
427 Normal(100),
428 Missing2,
429 Normal(97),
430 Normal(100),
431 Normal(96),
432 ]
433 ),
434 }
435}