Skip to main content

grib/
decoder.rs

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