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},
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        let mut pos = 0;
105        let sect5_param = Section5::try_from_slice(&sect5_bytes, &mut pos)
106            .map_err(|e| GribError::DecodeError(DecodeError::from(e)))?;
107        let sect6_bytes = match sect6_bytes[5] {
108            0x00 => sect6_bytes,
109            0xff => {
110                let mut sect6_bytes = sect6_bytes;
111                sect6_bytes.append(&mut dummy_bitmap_for_nonnullable_data(num_points_total));
112                sect6_bytes
113            }
114            n => {
115                return Err(GribError::DecodeError(DecodeError::NotSupported(
116                    "GRIB2 code table 6.0 (bit map indicator)",
117                    n.into(),
118                )));
119            }
120        };
121
122        Ok(Self {
123            num_points_total,
124            sect5_param,
125            sect6_bytes,
126            sect7_bytes,
127        })
128    }
129
130    /// Sets up a decoder for grid point values of `submessage`.
131    pub fn from<R: Grib2Read>(submessage: SubMessage<R>) -> Result<Self, GribError> {
132        let mut reader = submessage.9;
133        let sect5 = submessage.5.body;
134        let sect6 = submessage.6.body;
135        let sect7 = submessage.7.body;
136        let sect3_body = match submessage.3.body.body.as_ref() {
137            Some(SectionBody::Section3(b3)) => b3,
138            _ => return Err(GribError::InternalDataError),
139        };
140        let sect3_num_points = sect3_body.num_points() as usize;
141
142        Self::new(
143            sect3_num_points,
144            reader.read_sect_as_slice(sect5)?,
145            reader.read_sect_as_slice(sect6)?,
146            reader.read_sect_as_slice(sect7)?,
147        )
148    }
149
150    /// Dispatches a decoding process and gets an iterator of decoded values.
151    pub fn dispatch(
152        &self,
153    ) -> Result<Grib2DecodedValues<'_, impl Iterator<Item = f32> + '_>, GribError> {
154        let decoder = match &self.sect5_param.payload.template {
155            DataRepresentationTemplate::_5_0(template) => {
156                Grib2ValueIterator::SigSTNS(simple::Simple(self, template).iter()?)
157            }
158            DataRepresentationTemplate::_5_2(template) => {
159                Grib2ValueIterator::SigSC(complex::Complex(self, template).iter()?)
160            }
161            DataRepresentationTemplate::_5_3(template) => {
162                Grib2ValueIterator::SigSSCI(complex::ComplexSpatial(self, template).iter()?)
163            }
164            #[cfg(any(
165                feature = "jpeg2000-unpack-with-openjpeg",
166                feature = "jpeg2000-unpack-with-hayro"
167            ))]
168            DataRepresentationTemplate::_5_40(template) => {
169                Grib2ValueIterator::SigSIm(jpeg2000::Jpeg2000(self, template).iter()?)
170            }
171            #[cfg(feature = "png-unpack-with-png-crate")]
172            DataRepresentationTemplate::_5_41(template) => {
173                Grib2ValueIterator::SigSNV(png::Png(self, template).iter()?)
174            }
175            #[cfg(any(
176                feature = "ccsds-unpack-with-libaec",
177                feature = "ccsds-unpack-with-rust-aec"
178            ))]
179            DataRepresentationTemplate::_5_42(template) => {
180                Grib2ValueIterator::SigSNV(ccsds::Ccsds(self, template).iter()?)
181            }
182            DataRepresentationTemplate::_5_200(template) => {
183                Grib2ValueIterator::SigI(run_length::RunLength(self, template).iter()?)
184            }
185            #[allow(unreachable_patterns)]
186            _ => {
187                return Err(GribError::DecodeError(DecodeError::NotSupported(
188                    "GRIB2 code table 5.0 (data representation template number)",
189                    self.sect5_param.payload.template_num,
190                )));
191            }
192        };
193
194        let bitmap_slice = &self.sect6_bytes[6..];
195        bitmap::check_consistency(
196            self.num_points_total,
197            self.num_encoded_points(),
198            bitmap_slice,
199        )?;
200        let decoder =
201            BitmapDecodeIterator::new(bitmap_slice.iter(), decoder, self.num_points_total);
202        Ok(Grib2DecodedValues(decoder))
203    }
204
205    pub(crate) fn num_encoded_points(&self) -> usize {
206        self.sect5_param.payload.num_encoded_points as usize
207    }
208
209    pub(crate) fn sect7_payload(&self) -> &[u8] {
210        &self.sect7_bytes[5..]
211    }
212
213    /// Provides access to the parameters in Section 5.
214    ///
215    /// # Examples
216    /// ```
217    /// use grib::Grib2SubmessageDecoder;
218    ///
219    /// fn main() -> Result<(), Box<dyn std::error::Error>> {
220    ///     let f = std::fs::File::open(
221    ///         "testdata/Z__C_RJTD_20160822020000_NOWC_GPV_Ggis10km_Pphw10_FH0000-0100_grib2.bin",
222    ///     )?;
223    ///     let f = std::io::BufReader::new(f);
224    ///     let grib2 = grib::from_reader(f)?;
225    ///     let (_index, first_submessage) = grib2.iter().next().unwrap();
226    ///
227    ///     let decoder = Grib2SubmessageDecoder::from(first_submessage)?;
228    ///     let actual = decoder.section5();
229    ///     let expected = grib::def::grib2::Section5 {
230    ///         header: grib::def::grib2::SectionHeader {
231    ///             len: 23,
232    ///             sect_num: 5,
233    ///         },
234    ///         payload: grib::def::grib2::Section5Payload {
235    ///             num_encoded_points: 86016,
236    ///             template_num: 200,
237    ///             template: grib::def::grib2::DataRepresentationTemplate::_5_200(
238    ///                 grib::def::grib2::template::Template5_200 {
239    ///                     num_bits: 8,
240    ///                     max_val: 3,
241    ///                     max_level: 3,
242    ///                     dec: 0,
243    ///                     level_vals: vec![1, 2, 3],
244    ///                 },
245    ///             ),
246    ///         },
247    ///     };
248    ///     assert_eq!(actual, &expected);
249    ///
250    ///     Ok(())
251    /// }
252    /// ```
253    pub fn section5(&self) -> &Section5 {
254        &self.sect5_param
255    }
256}
257
258pub(crate) fn orig_field_type_is_supported(orig_field_type: u8) -> Result<(), DecodeError> {
259    if orig_field_type != 0 {
260        return Err(DecodeError::NotSupported(
261            "GRIB2 code table 5.1 (type of original field values)",
262            orig_field_type.into(),
263        ));
264    }
265    Ok(())
266}
267
268pub struct Grib2DecodedValues<'b, I>(BitmapDecodeIterator<std::slice::Iter<'b, u8>, I>);
269
270impl<I> Iterator for Grib2DecodedValues<'_, I>
271where
272    I: Iterator<Item = f32>,
273{
274    type Item = f32;
275
276    fn next(&mut self) -> Option<Self::Item> {
277        let Self(inner) = self;
278        inner.next()
279    }
280
281    fn size_hint(&self) -> (usize, Option<usize>) {
282        let Self(inner) = self;
283        inner.size_hint()
284    }
285}
286
287enum Grib2ValueIterator<'d> {
288    SigSTNS(SimplePackingDecoder<std::iter::Take<NBitwiseIterator<&'d [u8]>>>),
289    SigSC(SimplePackingDecoder<ComplexPackingDecoded<'d>>),
290    SigSSCI(
291        SimplePackingDecoder<
292            complex::SpatialDifferencingDecodeIterator<ComplexPackingDecoded<'d>, IntoIter<i32>>,
293        >,
294    ),
295    #[allow(dead_code)]
296    SigSI(SimplePackingDecoder<IntoIter<i32>>),
297    #[cfg(any(
298        feature = "jpeg2000-unpack-with-openjpeg",
299        feature = "jpeg2000-unpack-with-hayro"
300    ))]
301    SigSIm(SimplePackingDecoder<self::jpeg2000::ImageIntoIter>),
302    #[allow(dead_code)]
303    SigSNV(SimplePackingDecoder<NBitwiseIterator<Vec<u8>>>),
304    SigI(IntoIter<f32>),
305}
306
307impl<'d> Iterator for Grib2ValueIterator<'d> {
308    type Item = f32;
309
310    fn next(&mut self) -> Option<Self::Item> {
311        match self {
312            Self::SigSTNS(inner) => inner.next(),
313            Self::SigSC(inner) => inner.next(),
314            Self::SigSSCI(inner) => inner.next(),
315            Self::SigSI(inner) => inner.next(),
316            #[cfg(any(
317                feature = "jpeg2000-unpack-with-openjpeg",
318                feature = "jpeg2000-unpack-with-hayro"
319            ))]
320            Self::SigSIm(inner) => inner.next(),
321            Self::SigSNV(inner) => inner.next(),
322            Self::SigI(inner) => inner.next(),
323        }
324    }
325
326    fn size_hint(&self) -> (usize, Option<usize>) {
327        match self {
328            Self::SigSTNS(inner) => inner.size_hint(),
329            Self::SigSC(inner) => inner.size_hint(),
330            Self::SigSSCI(inner) => inner.size_hint(),
331            Self::SigSI(inner) => inner.size_hint(),
332            #[cfg(any(
333                feature = "jpeg2000-unpack-with-openjpeg",
334                feature = "jpeg2000-unpack-with-hayro"
335            ))]
336            Self::SigSIm(inner) => inner.size_hint(),
337            Self::SigSNV(inner) => inner.size_hint(),
338            Self::SigI(inner) => inner.size_hint(),
339        }
340    }
341}
342
343#[derive(Debug, Clone, PartialEq, Eq, Hash)]
344#[non_exhaustive]
345pub enum DecodeError {
346    NotSupported(&'static str, u16),
347    LengthMismatch,
348    UnclassifiedError(String),
349}
350
351impl From<String> for DecodeError {
352    fn from(value: String) -> Self {
353        Self::UnclassifiedError(value)
354    }
355}
356
357impl From<&str> for DecodeError {
358    fn from(value: &str) -> Self {
359        Self::UnclassifiedError(value.to_owned())
360    }
361}
362
363pub(crate) trait Grib2GpvUnpack {
364    type Iter<'a>: Iterator<Item = f32>
365    where
366        Self: 'a;
367
368    fn iter<'a>(&'a self) -> Result<Self::Iter<'a>, DecodeError>;
369}
370
371mod bitmap;
372#[cfg(any(
373    feature = "ccsds-unpack-with-libaec",
374    feature = "ccsds-unpack-with-rust-aec"
375))]
376mod ccsds;
377mod complex;
378mod helpers;
379#[cfg(any(
380    feature = "jpeg2000-unpack-with-openjpeg",
381    feature = "jpeg2000-unpack-with-hayro"
382))]
383mod jpeg2000;
384#[cfg(feature = "png-unpack-with-png-crate")]
385mod png;
386mod run_length;
387mod simple;
388mod stream;
389#[cfg(test)]
390mod tests;