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::{create_bitmap_for_nonnullable_data, BitmapDecodeIterator},
12        complex::ComplexPackingDecodeError,
13        png::PngDecodeError,
14        run_length::RunLengthEncodingDecodeError,
15        simple::{SimplePackingDecodeError, SimplePackingDecodeIteratorWrapper},
16    },
17    error::*,
18    reader::Grib2Read,
19};
20
21/// Decoder for grid point values of GRIB2 submessages.
22///
23/// # Examples
24/// ```
25/// use grib::Grib2SubmessageDecoder;
26///
27/// fn main() -> Result<(), Box<dyn std::error::Error>> {
28///     let f =
29///         std::fs::File::open("testdata/CMC_glb_TMP_ISBL_1_latlon.24x.24_2021051800_P000.grib2")?;
30///     let f = std::io::BufReader::new(f);
31///     let grib2 = grib::from_reader(f)?;
32///     let (_index, first_submessage) = grib2.iter().next().unwrap();
33///
34///     let decoder = Grib2SubmessageDecoder::from(first_submessage)?;
35///     let mut decoded = decoder.dispatch()?;
36///     assert_eq!(decoded.size_hint(), (1126500, Some(1126500)));
37///
38///     let first_value = decoded.next();
39///     assert_eq!(first_value.map(|f| f.round()), Some(236.0_f32));
40///
41///     let last_value = decoded.nth(1126498);
42///     assert_eq!(last_value.map(|f| f.round()), Some(286.0_f32));
43///
44///     let next_to_last_value = decoded.next();
45///     assert_eq!(next_to_last_value, None);
46///     Ok(())
47/// }
48/// ```
49pub struct Grib2SubmessageDecoder {
50    num_points_total: usize,
51    pub(crate) num_points_encoded: usize,
52    template_num: u16,
53    pub(crate) sect5_payload: Box<[u8]>,
54    bitmap: Vec<u8>,
55    pub(crate) sect7_payload: Box<[u8]>,
56}
57
58impl Grib2SubmessageDecoder {
59    fn new(
60        num_points_total: usize,
61        num_points_encoded: usize,
62        template_num: u16,
63        sect5_payload: Box<[u8]>,
64        bitmap: Vec<u8>,
65        sect7_payload: Box<[u8]>,
66    ) -> Self {
67        Self {
68            num_points_total,
69            num_points_encoded,
70            template_num,
71            sect5_payload,
72            bitmap,
73            sect7_payload,
74        }
75    }
76
77    /// Sets up a decoder for grid point values of `submessage`.
78    pub fn from<R: Grib2Read>(submessage: SubMessage<R>) -> Result<Self, GribError> {
79        let mut reader = submessage.9;
80        let sect5 = submessage.5.body;
81        let sect6 = submessage.6.body;
82        let sect7 = submessage.7.body;
83        let (sect3_body, sect5_body, sect6_body) = match (
84            submessage.3.body.body.as_ref(),
85            sect5.body.as_ref(),
86            sect6.body.as_ref(),
87        ) {
88            (
89                Some(SectionBody::Section3(b3)),
90                Some(SectionBody::Section5(b5)),
91                Some(SectionBody::Section6(b6)),
92            ) => (b3, b5, b6),
93            _ => return Err(GribError::InternalDataError),
94        };
95        let sect3_num_points = sect3_body.num_points() as usize;
96
97        let bitmap = match sect6_body.bitmap_indicator {
98            0x00 => {
99                let sect6_data = reader.read_sect_payload_as_slice(sect6)?;
100                sect6_data[1..].into()
101            }
102            0xff => {
103                let num_points = sect3_num_points;
104                create_bitmap_for_nonnullable_data(num_points)
105            }
106            _ => {
107                return Err(GribError::DecodeError(
108                    DecodeError::BitMapIndicatorUnsupported,
109                ));
110            }
111        };
112
113        Ok(Self::new(
114            sect3_num_points,
115            sect5_body.num_points() as usize,
116            sect5_body.repr_tmpl_num(),
117            reader.read_sect_payload_as_slice(sect5)?,
118            bitmap,
119            reader.read_sect_payload_as_slice(sect7)?,
120        ))
121    }
122
123    /// Dispatches a decoding process and gets an iterator of decoded values.
124    pub fn dispatch(
125        &self,
126    ) -> Result<Grib2DecodedValues<'_, impl Iterator<Item = f32> + '_>, GribError> {
127        let decoder = match self.template_num {
128            0 => Grib2ValueIterator::Template0(simple::decode(self)?),
129            2 => Grib2ValueIterator::Template2(complex::decode_7_2(self)?),
130            3 => Grib2ValueIterator::Template3(complex::decode_7_3(self)?),
131            #[cfg(not(target_arch = "wasm32"))]
132            40 => Grib2ValueIterator::Template40(jpeg2000::decode(self)?),
133            41 => Grib2ValueIterator::Template41(png::decode(self)?),
134            200 => Grib2ValueIterator::Template200(run_length::decode(self)?),
135            _ => {
136                return Err(GribError::DecodeError(
137                    DecodeError::TemplateNumberUnsupported,
138                ))
139            }
140        };
141        let decoder =
142            BitmapDecodeIterator::new(self.bitmap.iter(), decoder, self.num_points_total)?;
143        Ok(Grib2DecodedValues(decoder))
144    }
145}
146
147pub struct Grib2DecodedValues<'b, I>(BitmapDecodeIterator<std::slice::Iter<'b, u8>, I>);
148
149impl<I> Iterator for Grib2DecodedValues<'_, I>
150where
151    I: Iterator<Item = f32>,
152{
153    type Item = f32;
154
155    fn next(&mut self) -> Option<Self::Item> {
156        let Self(inner) = self;
157        inner.next()
158    }
159
160    fn size_hint(&self) -> (usize, Option<usize>) {
161        let Self(inner) = self;
162        inner.size_hint()
163    }
164}
165
166// Rust does not allow modification of generics type parameters or where clauses
167// in conditonal compilation at this time. This is a trick to allow compilation
168// even when JPEG 2000 code stream format support is not available (there may be
169// a better way).
170#[cfg(target_arch = "wasm32")]
171type Grib2ValueIterator<T0, T2, T3, T41> =
172    Grib2SubmessageDecoderIteratorWrapper<T0, T2, T3, std::vec::IntoIter<f32>, T41>;
173#[cfg(not(target_arch = "wasm32"))]
174type Grib2ValueIterator<T0, T2, T3, T40, T41> =
175    Grib2SubmessageDecoderIteratorWrapper<T0, T2, T3, T40, T41>;
176
177enum Grib2SubmessageDecoderIteratorWrapper<T0, T2, T3, T40, T41> {
178    Template0(SimplePackingDecodeIteratorWrapper<T0>),
179    Template2(SimplePackingDecodeIteratorWrapper<T2>),
180    Template3(SimplePackingDecodeIteratorWrapper<T3>),
181    #[allow(dead_code)]
182    #[cfg(target_arch = "wasm32")]
183    Template40(PhantomData<T40>),
184    #[cfg(not(target_arch = "wasm32"))]
185    Template40(SimplePackingDecodeIteratorWrapper<T40>),
186    Template41(SimplePackingDecodeIteratorWrapper<T41>),
187    Template200(std::vec::IntoIter<f32>),
188}
189
190impl<T0, T2, T3, T40, T41> Iterator for Grib2SubmessageDecoderIteratorWrapper<T0, T2, T3, T40, T41>
191where
192    T0: Iterator,
193    <T0 as Iterator>::Item: ToPrimitive,
194    T2: Iterator,
195    <T2 as Iterator>::Item: ToPrimitive,
196    T3: Iterator,
197    <T3 as Iterator>::Item: ToPrimitive,
198    T40: Iterator,
199    <T40 as Iterator>::Item: ToPrimitive,
200    T41: Iterator,
201    <T41 as Iterator>::Item: ToPrimitive,
202{
203    type Item = f32;
204
205    fn next(&mut self) -> Option<Self::Item> {
206        match self {
207            Self::Template0(inner) => inner.next(),
208            Self::Template2(inner) => inner.next(),
209            Self::Template3(inner) => inner.next(),
210            #[cfg(not(target_arch = "wasm32"))]
211            Self::Template40(inner) => inner.next(),
212            #[cfg(target_arch = "wasm32")]
213            Self::Template40(_) => unreachable!(),
214            Self::Template41(inner) => inner.next(),
215            Self::Template200(inner) => inner.next(),
216        }
217    }
218
219    fn size_hint(&self) -> (usize, Option<usize>) {
220        match self {
221            Self::Template0(inner) => inner.size_hint(),
222            Self::Template2(inner) => inner.size_hint(),
223            Self::Template3(inner) => inner.size_hint(),
224            #[cfg(not(target_arch = "wasm32"))]
225            Self::Template40(inner) => inner.size_hint(),
226            #[cfg(target_arch = "wasm32")]
227            Self::Template40(_) => unreachable!(),
228            Self::Template41(inner) => inner.size_hint(),
229            Self::Template200(inner) => inner.size_hint(),
230        }
231    }
232}
233
234#[derive(Debug, Clone, PartialEq, Eq, Hash)]
235pub enum DecodeError {
236    TemplateNumberUnsupported,
237    BitMapIndicatorUnsupported,
238    SimplePackingDecodeError(SimplePackingDecodeError),
239    ComplexPackingDecodeError(ComplexPackingDecodeError),
240    #[cfg(not(target_arch = "wasm32"))]
241    Jpeg2000CodeStreamDecodeError(Jpeg2000CodeStreamDecodeError),
242    PngDecodeError(PngDecodeError),
243    RunLengthEncodingDecodeError(RunLengthEncodingDecodeError),
244    LengthMismatch,
245}
246
247impl From<SimplePackingDecodeError> for DecodeError {
248    fn from(e: SimplePackingDecodeError) -> Self {
249        Self::SimplePackingDecodeError(e)
250    }
251}
252
253impl From<ComplexPackingDecodeError> for DecodeError {
254    fn from(e: ComplexPackingDecodeError) -> Self {
255        Self::ComplexPackingDecodeError(e)
256    }
257}
258
259#[cfg(not(target_arch = "wasm32"))]
260impl From<Jpeg2000CodeStreamDecodeError> for DecodeError {
261    fn from(e: Jpeg2000CodeStreamDecodeError) -> Self {
262        Self::Jpeg2000CodeStreamDecodeError(e)
263    }
264}
265
266impl From<RunLengthEncodingDecodeError> for DecodeError {
267    fn from(e: RunLengthEncodingDecodeError) -> Self {
268        Self::RunLengthEncodingDecodeError(e)
269    }
270}
271
272mod bitmap;
273mod complex;
274#[cfg(not(target_arch = "wasm32"))]
275mod jpeg2000;
276mod param;
277mod png;
278mod run_length;
279mod simple;
280mod stream;