Skip to main content

grib/
decoder.rs

1use std::vec::IntoIter;
2
3use grib_template_helpers::TryFromSlice as _;
4
5use crate::{
6    context::{SectionBody, SubMessage},
7    decoder::{
8        bitmap::{BitmapDecodeIterator, dummy_bitmap_for_nonnullable_data},
9        complex::ComplexPackingDecoded,
10        simple::SimplePackingDecoder,
11        stream::NBitwiseIterator,
12    },
13    def::grib2::{DataRepresentationTemplate, Section5},
14    error::*,
15    reader::Grib2Read,
16};
17
18/// Decoder for grid point values of GRIB2 submessages.
19///
20/// # Examples
21/// ```
22/// use grib::Grib2SubmessageDecoder;
23///
24/// fn main() -> Result<(), Box<dyn std::error::Error>> {
25///     let f = std::fs::File::open(
26///         "testdata/Z__C_RJTD_20160822020000_NOWC_GPV_Ggis10km_Pphw10_FH0000-0100_grib2.bin",
27///     )?;
28///     let f = std::io::BufReader::new(f);
29///     let grib2 = grib::from_reader(f)?;
30///     let (_index, first_submessage) = grib2.iter().next().unwrap();
31///
32///     let decoder = Grib2SubmessageDecoder::from(first_submessage)?;
33///     let mut decoded = decoder.dispatch()?;
34///     assert_eq!(decoded.size_hint(), (86016, Some(86016)));
35///
36///     let first_value = decoded.next();
37///     assert_eq!(first_value.map(|f| f.is_nan()), Some(true));
38///
39///     let non_nan_value = decoded.find(|f| !f.is_nan());
40///     assert_eq!(non_nan_value.map(|f| f.round()), Some(1.0_f32));
41///
42///     let last_value = decoded.last();
43///     assert_eq!(last_value.map(|f| f.is_nan()), Some(true));
44///     Ok(())
45/// }
46/// ```
47///
48/// If the byte sequences for Sections 5, 6, and 7 of the GRIB2 data are known,
49/// and the number of grid points (described in Section 3) is also known, it is
50/// also possible to create a decoder instance by passing them to
51/// [`Grib2SubmessageDecoder::new`]. The example above is equivalent to the
52/// following:
53///
54/// ```
55/// use std::io::Read;
56///
57/// use grib::Grib2SubmessageDecoder;
58///
59/// fn main() -> Result<(), Box<dyn std::error::Error>> {
60///     let f = std::fs::File::open(
61///         "testdata/Z__C_RJTD_20160822020000_NOWC_GPV_Ggis10km_Pphw10_FH0000-0100_grib2.bin",
62///     )?;
63///     let mut f = std::io::BufReader::new(f);
64///     let mut buf = Vec::new();
65///     f.read_to_end(&mut buf)?;
66///
67///     let decoder = Grib2SubmessageDecoder::new(
68///         86016,
69///         buf[0x0000008f..0x000000a6].to_vec(),
70///         buf[0x000000a6..0x000000ac].to_vec(),
71///         buf[0x000000ac..0x0000061b].to_vec(),
72///     )?;
73///     let mut decoded = decoder.dispatch()?;
74///     assert_eq!(decoded.size_hint(), (86016, Some(86016)));
75///
76///     let first_value = decoded.next();
77///     assert_eq!(first_value.map(|f| f.is_nan()), Some(true));
78///
79///     let non_nan_value = decoded.find(|f| !f.is_nan());
80///     assert_eq!(non_nan_value.map(|f| f.round()), Some(1.0_f32));
81///
82///     let last_value = decoded.last();
83///     assert_eq!(last_value.map(|f| f.is_nan()), Some(true));
84///     Ok(())
85/// }
86/// ```
87pub struct Grib2SubmessageDecoder {
88    num_points_total: usize,
89    sect5_param: Section5,
90    sect6_bytes: Vec<u8>,
91    sect7_bytes: Vec<u8>,
92}
93
94impl Grib2SubmessageDecoder {
95    /// Creates an instance from the number of grid points (described in Section
96    /// 3) and byte sequences for Sections 5, 6, and 7 of the GRIB2 data.
97    ///
98    /// For code examples, refer to the description of this `struct`.
99    pub fn new(
100        num_points_total: usize,
101        sect5_bytes: Vec<u8>,
102        sect6_bytes: Vec<u8>,
103        sect7_bytes: Vec<u8>,
104    ) -> Result<Self, GribError> {
105        let mut pos = 0;
106        let sect5_param = Section5::try_from_slice(&sect5_bytes, &mut pos)
107            .map_err(|e| GribError::DecodeError(DecodeError::from(e)))?;
108        let sect6_bytes = match sect6_bytes[5] {
109            0x00 => sect6_bytes,
110            0xff => {
111                let mut sect6_bytes = sect6_bytes;
112                sect6_bytes.append(&mut dummy_bitmap_for_nonnullable_data(num_points_total));
113                sect6_bytes
114            }
115            n => {
116                return Err(GribError::DecodeError(DecodeError::NotSupported(
117                    "GRIB2 code table 6.0 (bit map indicator)",
118                    n.into(),
119                )));
120            }
121        };
122
123        Ok(Self {
124            num_points_total,
125            sect5_param,
126            sect6_bytes,
127            sect7_bytes,
128        })
129    }
130
131    /// Sets up a decoder for grid point values of `submessage`.
132    pub fn from<R: Grib2Read>(submessage: SubMessage<R>) -> Result<Self, GribError> {
133        let mut reader = submessage.9;
134        let sect5 = submessage.5.body;
135        let sect6 = submessage.6.body;
136        let sect7 = submessage.7.body;
137        let sect3_body = match submessage.3.body.body.as_ref() {
138            Some(SectionBody::Section3(b3)) => b3,
139            _ => return Err(GribError::InternalDataError),
140        };
141        let sect3_num_points = sect3_body.num_points() as usize;
142
143        Self::new(
144            sect3_num_points,
145            reader.read_sect_as_slice(sect5)?,
146            reader.read_sect_as_slice(sect6)?,
147            reader.read_sect_as_slice(sect7)?,
148        )
149    }
150
151    /// Dispatches a decoding process and gets an iterator of decoded values.
152    pub fn dispatch(
153        &self,
154    ) -> Result<Grib2DecodedValues<'_, impl Iterator<Item = f32> + '_>, GribError> {
155        let decoder = match &self.sect5_param.payload.template {
156            DataRepresentationTemplate::_5_0(template) => {
157                Grib2ValueIterator::SigSTNS(simple::Simple(self, template).iter()?)
158            }
159            DataRepresentationTemplate::_5_2(template) => {
160                Grib2ValueIterator::SigSC(complex::Complex(self, template).iter()?)
161            }
162            DataRepresentationTemplate::_5_3(template) => {
163                Grib2ValueIterator::SigSSCI(complex::ComplexSpatial(self, template).iter()?)
164            }
165            #[cfg(any(
166                feature = "jpeg2000-unpack-with-openjpeg",
167                feature = "jpeg2000-unpack-with-hayro"
168            ))]
169            DataRepresentationTemplate::_5_40(template) => {
170                Grib2ValueIterator::SigSIm(jpeg2000::Jpeg2000(self, template).iter()?)
171            }
172            #[cfg(feature = "png-unpack-with-png-crate")]
173            DataRepresentationTemplate::_5_41(template) => {
174                Grib2ValueIterator::SigSNV(png::Png(self, template).iter()?)
175            }
176            #[cfg(any(
177                feature = "ccsds-unpack-with-libaec",
178                feature = "ccsds-unpack-with-rust-aec"
179            ))]
180            DataRepresentationTemplate::_5_42(template) => {
181                Grib2ValueIterator::SigSNV(ccsds::Ccsds(self, template).iter()?)
182            }
183            DataRepresentationTemplate::_5_200(template) => {
184                Grib2ValueIterator::SigI(run_length::RunLength(self, template).iter()?)
185            }
186            #[allow(unreachable_patterns)]
187            _ => {
188                return Err(GribError::DecodeError(DecodeError::NotSupported(
189                    "GRIB2 code table 5.0 (data representation template number)",
190                    self.sect5_param.payload.template_num,
191                )));
192            }
193        };
194
195        let bitmap_slice = &self.sect6_bytes[6..];
196        bitmap::check_consistency(
197            self.num_points_total,
198            self.num_encoded_points(),
199            bitmap_slice,
200        )?;
201        let decoder =
202            BitmapDecodeIterator::new(bitmap_slice.iter(), decoder, self.num_points_total);
203        Ok(Grib2DecodedValues(decoder))
204    }
205
206    pub(crate) fn num_encoded_points(&self) -> usize {
207        self.sect5_param.payload.num_encoded_points as usize
208    }
209
210    pub(crate) fn sect7_payload(&self) -> &[u8] {
211        &self.sect7_bytes[5..]
212    }
213
214    /// Provides access to the parameters in Section 5.
215    ///
216    /// # Examples
217    /// ```
218    /// use grib::Grib2SubmessageDecoder;
219    ///
220    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
221    ///     let f = std::fs::File::open(
222    ///         "testdata/Z__C_RJTD_20160822020000_NOWC_GPV_Ggis10km_Pphw10_FH0000-0100_grib2.bin",
223    ///     )?;
224    ///     let f = std::io::BufReader::new(f);
225    ///     let grib2 = grib::from_reader(f)?;
226    ///     let (_index, first_submessage) = grib2.iter().next().unwrap();
227    ///
228    ///     let decoder = Grib2SubmessageDecoder::from(first_submessage)?;
229    ///     let actual = decoder.section5();
230    ///     let expected = grib::def::grib2::Section5 {
231    ///         header: grib::def::grib2::SectionHeader {
232    ///             len: 23,
233    ///             sect_num: 5,
234    ///         },
235    ///         payload: grib::def::grib2::Section5Payload {
236    ///             num_encoded_points: 86016,
237    ///             template_num: 200,
238    ///             template: grib::def::grib2::DataRepresentationTemplate::_5_200(
239    ///                 grib::def::grib2::template::Template5_200 {
240    ///                     num_bits: 8,
241    ///                     max_val: 3,
242    ///                     max_level: 3,
243    ///                     dec: 0,
244    ///                     level_vals: vec![1, 2, 3],
245    ///                 },
246    ///             ),
247    ///         },
248    ///     };
249    ///     assert_eq!(actual, &expected);
250    ///
251    ///     Ok(())
252    /// }
253    /// ```
254    pub fn section5(&self) -> &Section5 {
255        &self.sect5_param
256    }
257}
258
259pub(crate) fn orig_field_type_is_supported(orig_field_type: u8) -> Result<(), DecodeError> {
260    if orig_field_type != 0 {
261        return Err(DecodeError::NotSupported(
262            "GRIB2 code table 5.1 (type of original field values)",
263            orig_field_type.into(),
264        ));
265    }
266    Ok(())
267}
268
269pub struct Grib2DecodedValues<'b, I>(BitmapDecodeIterator<std::slice::Iter<'b, u8>, I>);
270
271impl<I> Iterator for Grib2DecodedValues<'_, I>
272where
273    I: Iterator<Item = f32>,
274{
275    type Item = f32;
276
277    fn next(&mut self) -> Option<Self::Item> {
278        let Self(inner) = self;
279        inner.next()
280    }
281
282    fn size_hint(&self) -> (usize, Option<usize>) {
283        let Self(inner) = self;
284        inner.size_hint()
285    }
286}
287
288enum Grib2ValueIterator<'d> {
289    SigSTNS(SimplePackingDecoder<std::iter::Take<NBitwiseIterator<&'d [u8]>>>),
290    SigSC(SimplePackingDecoder<ComplexPackingDecoded<'d>>),
291    SigSSCI(
292        SimplePackingDecoder<
293            complex::SpatialDifferencingDecodeIterator<ComplexPackingDecoded<'d>, IntoIter<i32>>,
294        >,
295    ),
296    #[allow(dead_code)]
297    SigSI(SimplePackingDecoder<IntoIter<i32>>),
298    #[cfg(any(
299        feature = "jpeg2000-unpack-with-openjpeg",
300        feature = "jpeg2000-unpack-with-hayro"
301    ))]
302    SigSIm(SimplePackingDecoder<self::jpeg2000::ImageIntoIter>),
303    #[allow(dead_code)]
304    SigSNV(SimplePackingDecoder<NBitwiseIterator<Vec<u8>>>),
305    SigI(IntoIter<f32>),
306}
307
308impl<'d> Iterator for Grib2ValueIterator<'d> {
309    type Item = f32;
310
311    fn next(&mut self) -> Option<Self::Item> {
312        match self {
313            Self::SigSTNS(inner) => inner.next(),
314            Self::SigSC(inner) => inner.next(),
315            Self::SigSSCI(inner) => inner.next(),
316            Self::SigSI(inner) => inner.next(),
317            #[cfg(any(
318                feature = "jpeg2000-unpack-with-openjpeg",
319                feature = "jpeg2000-unpack-with-hayro"
320            ))]
321            Self::SigSIm(inner) => inner.next(),
322            Self::SigSNV(inner) => inner.next(),
323            Self::SigI(inner) => inner.next(),
324        }
325    }
326
327    fn size_hint(&self) -> (usize, Option<usize>) {
328        match self {
329            Self::SigSTNS(inner) => inner.size_hint(),
330            Self::SigSC(inner) => inner.size_hint(),
331            Self::SigSSCI(inner) => inner.size_hint(),
332            Self::SigSI(inner) => inner.size_hint(),
333            #[cfg(any(
334                feature = "jpeg2000-unpack-with-openjpeg",
335                feature = "jpeg2000-unpack-with-hayro"
336            ))]
337            Self::SigSIm(inner) => inner.size_hint(),
338            Self::SigSNV(inner) => inner.size_hint(),
339            Self::SigI(inner) => inner.size_hint(),
340        }
341    }
342}
343
344#[derive(Debug, Clone, PartialEq, Eq, Hash)]
345#[non_exhaustive]
346pub enum DecodeError {
347    NotSupported(&'static str, u16),
348    LengthMismatch,
349    UnclassifiedError(String),
350}
351
352impl From<String> for DecodeError {
353    fn from(value: String) -> Self {
354        Self::UnclassifiedError(value)
355    }
356}
357
358impl From<&str> for DecodeError {
359    fn from(value: &str) -> Self {
360        Self::UnclassifiedError(value.to_owned())
361    }
362}
363
364pub(crate) trait Grib2GpvUnpack {
365    type Iter<'a>: Iterator<Item = f32>
366    where
367        Self: 'a;
368
369    fn iter<'a>(&'a self) -> Result<Self::Iter<'a>, DecodeError>;
370}
371
372mod bitmap;
373#[cfg(any(
374    feature = "ccsds-unpack-with-libaec",
375    feature = "ccsds-unpack-with-rust-aec"
376))]
377mod ccsds;
378mod complex;
379mod helpers;
380#[cfg(any(
381    feature = "jpeg2000-unpack-with-openjpeg",
382    feature = "jpeg2000-unpack-with-hayro"
383))]
384mod jpeg2000;
385#[cfg(feature = "png-unpack-with-png-crate")]
386mod png;
387mod run_length;
388mod simple;
389mod stream;
390#[cfg(test)]
391mod tests;