use num::ToPrimitive;
use crate::{
DecodeError, Grib2GpvUnpack,
decoder::{
Grib2SubmessageDecoder,
stream::{FixedValueIterator, NBitwiseIterator},
},
def::grib2::template::param_set,
};
pub(crate) enum SimplePackingDecoder<I> {
ZeroLength(FixedValueIterator<f32>),
NonZeroLength(NonZeroSimplePackingDecoder<I>),
}
impl<I, N> Iterator for SimplePackingDecoder<I>
where
I: Iterator<Item = N>,
N: ToPrimitive,
{
type Item = f32;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::ZeroLength(inner) => inner.next(),
Self::NonZeroLength(inner) => inner.next(),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
Self::ZeroLength(inner) => inner.size_hint(),
Self::NonZeroLength(inner) => inner.size_hint(),
}
}
}
pub(crate) struct Simple<'d>(
pub(crate) &'d Grib2SubmessageDecoder,
pub(crate) &'d crate::def::grib2::template::Template5_0,
);
impl<'d> Grib2GpvUnpack for Simple<'d> {
type Iter<'a>
= SimplePackingDecoder<std::iter::Take<NBitwiseIterator<&'d [u8]>>>
where
Self: 'a;
fn iter<'a>(&'a self) -> Result<Self::Iter<'d>, DecodeError> {
let Self(target, template) = self;
super::orig_field_type_is_supported(template.orig_field_type)?;
let decoder = if template.simple.num_bits == 0 {
SimplePackingDecoder::ZeroLength(FixedValueIterator::new(
template.simple.zero_bit_reference_value(),
target.num_encoded_points(),
))
} else {
let iter = NBitwiseIterator::new(
target.sect7_payload(),
usize::from(template.simple.num_bits),
)
.take(target.num_encoded_points());
let iter = NonZeroSimplePackingDecoder::new(iter, &template.simple);
SimplePackingDecoder::NonZeroLength(iter)
};
Ok(decoder)
}
}
pub(crate) struct NonZeroSimplePackingDecoder<I> {
iter: I,
ref_val: f32,
exp: i32,
dec: i32,
}
impl<I> NonZeroSimplePackingDecoder<I> {
pub(crate) fn new(iter: I, param: ¶m_set::SimplePacking) -> Self {
Self {
iter,
ref_val: param.ref_val,
exp: param.exp.into(),
dec: param.dec.into(),
}
}
}
impl<I: Iterator<Item = N>, N: ToPrimitive> Iterator for NonZeroSimplePackingDecoder<I> {
type Item = f32;
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
Some(encoded) => {
let encoded = encoded.to_f32().unwrap();
let diff = encoded * 2_f32.powi(self.exp);
let dig_factor = 10_f32.powi(-self.dec);
let value: f32 = (self.ref_val + diff) * dig_factor;
Some(value)
}
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use std::{
fs::File,
io::{BufReader, Read},
};
use grib_template_helpers::TryFromSlice as _;
use super::*;
#[test]
fn decode_simple_packing() {
let buf = vec![0x35, 0x3e, 0x6b, 0xf6, 0x80, 0x1a, 0x00, 0x00, 0x10, 0x00];
let mut pos = 0;
let param = param_set::SimplePacking::try_from_slice(&buf, &mut pos).unwrap();
let input: Vec<u8> = vec![0x00, 0x06, 0x00, 0x0d];
let expected: Vec<f32> = vec![7.987_831_6e-7, 9.030_913e-7];
let iter = NBitwiseIterator::new(&input, usize::from(param.num_bits));
let actual = NonZeroSimplePackingDecoder::new(iter, ¶m).collect::<Vec<_>>();
assert_eq!(actual.len(), expected.len());
let mut i = 0;
while i < actual.len() {
assert!(actual[i] < expected[i] + 0.00000001);
assert!(actual[i] > expected[i] - 0.00000001);
i += 1;
}
}
#[test]
fn simple_packing_length() {
let length = 9;
let sect5 = vec![
0x00, 0x00, 0x00, 0x15, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
];
let sect6 = vec![0x00, 0x00, 0x00, 0x06, 0x06, 0xff];
let sect7 = vec![0x00, 0x00, 0x00, 0x0a, 0x07, 0x01, 0x23, 0x45, 0x67, 0x80];
let decoder = Grib2SubmessageDecoder::new(length, sect5, sect6, sect7).unwrap();
let decoded = decoder.dispatch().unwrap();
assert_eq!(decoded.size_hint(), (length, Some(length)));
let actual = decoded.collect::<Vec<_>>().len();
assert_eq!(actual, length);
}
#[test]
fn decode_simple_packing_when_nbit_is_zero() {
let f = File::open(
"testdata/icon_global_icosahedral_single-level_2021112018_000_TOT_PREC.grib2",
)
.unwrap();
let mut f = BufReader::new(f);
let mut buf = Vec::new();
f.read_to_end(&mut buf).unwrap();
let decoder = Grib2SubmessageDecoder::new(
2949120,
buf[0x0000009d..0x000000b2].to_vec(),
buf[0x000000b2..0x000000b8].to_vec(),
buf[0x000000b8..0x000000bd].to_vec(),
)
.unwrap();
let actual = decoder.dispatch().unwrap().collect::<Vec<_>>();
let expected = vec![0f32; 0x002d0000];
assert_eq!(actual, expected);
}
}