grib/
decoder.rs

1#[cfg(target_arch = "wasm32")]
2use std::marker::PhantomData;
3
4use num::ToPrimitive;
5
6#[cfg(not(target_arch = "wasm32"))]
7use crate::decoder::jpeg2000::Jpeg2000CodeStreamDecodeError;
8use crate::{
9    context::{SectionBody, SubMessage},
10    decoder::{
11        bitmap::{dummy_bitmap_for_nonnullable_data, BitmapDecodeIterator},
12        complex::ComplexPackingDecodeError,
13        param::Section5Param,
14        png::PngDecodeError,
15        run_length::RunLengthEncodingDecodeError,
16        simple::{SimplePackingDecodeError, SimplePackingDecodeIteratorWrapper},
17    },
18    error::*,
19    reader::Grib2Read,
20};
21
22/// Decoder for grid point values of GRIB2 submessages.
23///
24/// # Examples
25/// ```
26/// use grib::Grib2SubmessageDecoder;
27///
28/// fn main() -> Result<(), Box<dyn std::error::Error>> {
29///     let f =
30///         std::fs::File::open("testdata/CMC_glb_TMP_ISBL_1_latlon.24x.24_2021051800_P000.grib2")?;
31///     let f = std::io::BufReader::new(f);
32///     let grib2 = grib::from_reader(f)?;
33///     let (_index, first_submessage) = grib2.iter().next().unwrap();
34///
35///     let decoder = Grib2SubmessageDecoder::from(first_submessage)?;
36///     let mut decoded = decoder.dispatch()?;
37///     assert_eq!(decoded.size_hint(), (1126500, Some(1126500)));
38///
39///     let first_value = decoded.next();
40///     assert_eq!(first_value.map(|f| f.round()), Some(236.0_f32));
41///
42///     let last_value = decoded.nth(1126498);
43///     assert_eq!(last_value.map(|f| f.round()), Some(286.0_f32));
44///
45///     let next_to_last_value = decoded.next();
46///     assert_eq!(next_to_last_value, None);
47///     Ok(())
48/// }
49/// ```
50///
51/// If the byte sequences for Sections 5, 6, and 7 of the GRIB2 data are known,
52/// and the number of grid points (described in Section 3) is also known, it is
53/// also possible to create a decoder instance by passing them to
54/// [`Grib2SubmessageDecoder::new`]. The example above is equivalent to the
55/// following:
56///
57/// ```
58/// use std::io::Read;
59///
60/// use grib::Grib2SubmessageDecoder;
61///
62/// fn main() -> Result<(), Box<dyn std::error::Error>> {
63///     let f =
64///         std::fs::File::open("testdata/CMC_glb_TMP_ISBL_1_latlon.24x.24_2021051800_P000.grib2")?;
65///     let mut f = std::io::BufReader::new(f);
66///     let mut buf = Vec::new();
67///     f.read_to_end(&mut buf)?;
68///
69///     let decoder = Grib2SubmessageDecoder::new(
70///         1126500,
71///         buf[0x0000008f..0x000000a6].to_vec(),
72///         buf[0x000000a6..0x000000ac].to_vec(),
73///         buf[0x000000ac..0x0003d6c7].to_vec(),
74///     )?;
75///     let mut decoded = decoder.dispatch()?;
76///     assert_eq!(decoded.size_hint(), (1126500, Some(1126500)));
77///
78///     let first_value = decoded.next();
79///     assert_eq!(first_value.map(|f| f.round()), Some(236.0_f32));
80///
81///     let last_value = decoded.nth(1126498);
82///     assert_eq!(last_value.map(|f| f.round()), Some(286.0_f32));
83///
84///     let next_to_last_value = decoded.next();
85///     assert_eq!(next_to_last_value, None);
86///     Ok(())
87/// }
88/// ```
89pub struct Grib2SubmessageDecoder {
90    num_points_total: usize,
91    sect5_param: Section5Param,
92    pub(crate) sect5_bytes: Vec<u8>,
93    sect6_bytes: Vec<u8>,
94    sect7_bytes: Vec<u8>,
95}
96
97impl Grib2SubmessageDecoder {
98    /// Creates an instance from the number of grid points (described in Section
99    /// 3) and byte sequences for Sections 5, 6, and 7 of the GRIB2 data.
100    ///
101    /// For code examples, refer to the description of this `struct`.
102    pub fn new(
103        num_points_total: usize,
104        sect5_bytes: Vec<u8>,
105        sect6_bytes: Vec<u8>,
106        sect7_bytes: Vec<u8>,
107    ) -> Result<Self, GribError> {
108        let sect5_param = Section5Param::from_buf(&sect5_bytes[5..11]);
109        let sect6_bytes = match sect6_bytes[5] {
110            0x00 => sect6_bytes,
111            0xff => {
112                let mut sect6_bytes = sect6_bytes;
113                sect6_bytes.append(&mut dummy_bitmap_for_nonnullable_data(num_points_total));
114                sect6_bytes
115            }
116            _ => {
117                return Err(GribError::DecodeError(
118                    DecodeError::BitMapIndicatorUnsupported,
119                ))
120            }
121        };
122
123        Ok(Self {
124            num_points_total,
125            sect5_param,
126            sect5_bytes,
127            sect6_bytes,
128            sect7_bytes,
129        })
130    }
131
132    /// Sets up a decoder for grid point values of `submessage`.
133    pub fn from<R: Grib2Read>(submessage: SubMessage<R>) -> Result<Self, GribError> {
134        let mut reader = submessage.9;
135        let sect5 = submessage.5.body;
136        let sect6 = submessage.6.body;
137        let sect7 = submessage.7.body;
138        let sect3_body = match submessage.3.body.body.as_ref() {
139            Some(SectionBody::Section3(b3)) => b3,
140            _ => return Err(GribError::InternalDataError),
141        };
142        let sect3_num_points = sect3_body.num_points() as usize;
143
144        Self::new(
145            sect3_num_points,
146            reader.read_sect_as_slice(sect5)?,
147            reader.read_sect_as_slice(sect6)?,
148            reader.read_sect_as_slice(sect7)?,
149        )
150    }
151
152    /// Dispatches a decoding process and gets an iterator of decoded values.
153    pub fn dispatch(
154        &self,
155    ) -> Result<Grib2DecodedValues<'_, impl Iterator<Item = f32> + '_>, GribError> {
156        let decoder = match self.sect5_param.template_num {
157            0 => Grib2ValueIterator::Template0(simple::decode(self)?),
158            2 => Grib2ValueIterator::Template2(complex::decode_7_2(self)?),
159            3 => Grib2ValueIterator::Template3(complex::decode_7_3(self)?),
160            #[cfg(not(target_arch = "wasm32"))]
161            40 => Grib2ValueIterator::Template40(jpeg2000::decode(self)?),
162            41 => Grib2ValueIterator::Template41(png::decode(self)?),
163            #[cfg(not(target_arch = "wasm32"))]
164            42 => Grib2ValueIterator::Template42(ccsds::decode(self)?),
165            200 => Grib2ValueIterator::Template200(run_length::decode(self)?),
166            _ => {
167                return Err(GribError::DecodeError(
168                    DecodeError::TemplateNumberUnsupported,
169                ))
170            }
171        };
172        let decoder = BitmapDecodeIterator::new(
173            self.sect6_bytes[6..].iter(),
174            decoder,
175            self.num_points_total,
176        )?;
177        Ok(Grib2DecodedValues(decoder))
178    }
179
180    pub(crate) fn num_points_encoded(&self) -> usize {
181        self.sect5_param.num_points_encoded as usize
182    }
183
184    pub(crate) fn sect7_payload(&self) -> &[u8] {
185        &self.sect7_bytes[5..]
186    }
187}
188
189pub struct Grib2DecodedValues<'b, I>(BitmapDecodeIterator<std::slice::Iter<'b, u8>, I>);
190
191impl<I> Iterator for Grib2DecodedValues<'_, I>
192where
193    I: Iterator<Item = f32>,
194{
195    type Item = f32;
196
197    fn next(&mut self) -> Option<Self::Item> {
198        let Self(inner) = self;
199        inner.next()
200    }
201
202    fn size_hint(&self) -> (usize, Option<usize>) {
203        let Self(inner) = self;
204        inner.size_hint()
205    }
206}
207
208// Rust does not allow modification of generics type parameters or where clauses
209// in conditonal compilation at this time. This is a trick to allow compilation
210// even when JPEG 2000 code stream format support is not available (there may be
211// a better way).
212#[cfg(target_arch = "wasm32")]
213type Grib2ValueIterator<T0, T2, T3, T41> = Grib2SubmessageDecoderIteratorWrapper<
214    T0,
215    T2,
216    T3,
217    std::vec::IntoIter<f32>,
218    T41,
219    std::vec::IntoIter<f32>,
220>;
221#[cfg(not(target_arch = "wasm32"))]
222type Grib2ValueIterator<T0, T2, T3, T40, T41, T42> =
223    Grib2SubmessageDecoderIteratorWrapper<T0, T2, T3, T40, T41, T42>;
224
225enum Grib2SubmessageDecoderIteratorWrapper<T0, T2, T3, T40, T41, T42> {
226    Template0(SimplePackingDecodeIteratorWrapper<T0>),
227    Template2(SimplePackingDecodeIteratorWrapper<T2>),
228    Template3(SimplePackingDecodeIteratorWrapper<T3>),
229    #[allow(dead_code)]
230    #[cfg(target_arch = "wasm32")]
231    Template40(PhantomData<T40>),
232    #[cfg(not(target_arch = "wasm32"))]
233    Template40(SimplePackingDecodeIteratorWrapper<T40>),
234    Template41(SimplePackingDecodeIteratorWrapper<T41>),
235    #[allow(dead_code)]
236    #[cfg(target_arch = "wasm32")]
237    Template42(PhantomData<T42>),
238    #[cfg(not(target_arch = "wasm32"))]
239    Template42(SimplePackingDecodeIteratorWrapper<T42>),
240    Template200(std::vec::IntoIter<f32>),
241}
242
243impl<T0, T2, T3, T40, T41, T42> Iterator
244    for Grib2SubmessageDecoderIteratorWrapper<T0, T2, T3, T40, T41, T42>
245where
246    T0: Iterator,
247    <T0 as Iterator>::Item: ToPrimitive,
248    T2: Iterator,
249    <T2 as Iterator>::Item: ToPrimitive,
250    T3: Iterator,
251    <T3 as Iterator>::Item: ToPrimitive,
252    T40: Iterator,
253    <T40 as Iterator>::Item: ToPrimitive,
254    T41: Iterator,
255    <T41 as Iterator>::Item: ToPrimitive,
256    T42: Iterator,
257    <T42 as Iterator>::Item: ToPrimitive,
258{
259    type Item = f32;
260
261    fn next(&mut self) -> Option<Self::Item> {
262        match self {
263            Self::Template0(inner) => inner.next(),
264            Self::Template2(inner) => inner.next(),
265            Self::Template3(inner) => inner.next(),
266            #[cfg(not(target_arch = "wasm32"))]
267            Self::Template40(inner) => inner.next(),
268            #[cfg(target_arch = "wasm32")]
269            Self::Template40(_) => unreachable!(),
270            Self::Template41(inner) => inner.next(),
271            #[cfg(not(target_arch = "wasm32"))]
272            Self::Template42(inner) => inner.next(),
273            #[cfg(target_arch = "wasm32")]
274            Self::Template42(_) => unreachable!(),
275            Self::Template200(inner) => inner.next(),
276        }
277    }
278
279    fn size_hint(&self) -> (usize, Option<usize>) {
280        match self {
281            Self::Template0(inner) => inner.size_hint(),
282            Self::Template2(inner) => inner.size_hint(),
283            Self::Template3(inner) => inner.size_hint(),
284            #[cfg(not(target_arch = "wasm32"))]
285            Self::Template40(inner) => inner.size_hint(),
286            #[cfg(target_arch = "wasm32")]
287            Self::Template40(_) => unreachable!(),
288            Self::Template41(inner) => inner.size_hint(),
289            #[cfg(not(target_arch = "wasm32"))]
290            Self::Template42(inner) => inner.size_hint(),
291            #[cfg(target_arch = "wasm32")]
292            Self::Template42(_) => unreachable!(),
293            Self::Template200(inner) => inner.size_hint(),
294        }
295    }
296}
297
298#[derive(Debug, Clone, PartialEq, Eq, Hash)]
299pub enum DecodeError {
300    TemplateNumberUnsupported,
301    BitMapIndicatorUnsupported,
302    SimplePackingDecodeError(SimplePackingDecodeError),
303    ComplexPackingDecodeError(ComplexPackingDecodeError),
304    #[cfg(not(target_arch = "wasm32"))]
305    Jpeg2000CodeStreamDecodeError(Jpeg2000CodeStreamDecodeError),
306    PngDecodeError(PngDecodeError),
307    RunLengthEncodingDecodeError(RunLengthEncodingDecodeError),
308    LengthMismatch,
309    Unknown(String),
310}
311
312impl From<SimplePackingDecodeError> for DecodeError {
313    fn from(e: SimplePackingDecodeError) -> Self {
314        Self::SimplePackingDecodeError(e)
315    }
316}
317
318impl From<ComplexPackingDecodeError> for DecodeError {
319    fn from(e: ComplexPackingDecodeError) -> Self {
320        Self::ComplexPackingDecodeError(e)
321    }
322}
323
324#[cfg(not(target_arch = "wasm32"))]
325impl From<Jpeg2000CodeStreamDecodeError> for DecodeError {
326    fn from(e: Jpeg2000CodeStreamDecodeError) -> Self {
327        Self::Jpeg2000CodeStreamDecodeError(e)
328    }
329}
330
331impl From<RunLengthEncodingDecodeError> for DecodeError {
332    fn from(e: RunLengthEncodingDecodeError) -> Self {
333        Self::RunLengthEncodingDecodeError(e)
334    }
335}
336
337mod bitmap;
338#[cfg(not(target_arch = "wasm32"))]
339mod ccsds;
340mod complex;
341#[cfg(not(target_arch = "wasm32"))]
342mod jpeg2000;
343mod param;
344mod png;
345mod run_length;
346mod simple;
347mod stream;