use std::vec::IntoIter;
use grib_template_helpers::TryFromSlice as _;
use crate::{
context::{SectionBody, SubMessage},
decoder::{
bitmap::{BitmapDecodeIterator, dummy_bitmap_for_nonnullable_data},
complex::ComplexPackingDecoded,
simple::SimplePackingDecoder,
stream::NBitwiseIterator,
},
def::grib2::{DataRepresentationTemplate, Section5},
error::*,
reader::Grib2Read,
};
pub struct Grib2SubmessageDecoder {
num_points_total: usize,
sect5_param: Section5,
sect6_bytes: Vec<u8>,
sect7_bytes: Vec<u8>,
}
impl Grib2SubmessageDecoder {
pub fn new(
num_points_total: usize,
sect5_bytes: Vec<u8>,
sect6_bytes: Vec<u8>,
sect7_bytes: Vec<u8>,
) -> Result<Self, GribError> {
let mut pos = 0;
let sect5_param = Section5::try_from_slice(§5_bytes, &mut pos)
.map_err(|e| GribError::DecodeError(DecodeError::from(e)))?;
let sect6_bytes = match sect6_bytes[5] {
0x00 => sect6_bytes,
0xff => {
let mut sect6_bytes = sect6_bytes;
sect6_bytes.append(&mut dummy_bitmap_for_nonnullable_data(num_points_total));
sect6_bytes
}
n => {
return Err(GribError::DecodeError(DecodeError::NotSupported(
"GRIB2 code table 6.0 (bit map indicator)",
n.into(),
)));
}
};
Ok(Self {
num_points_total,
sect5_param,
sect6_bytes,
sect7_bytes,
})
}
pub fn from<R: Grib2Read>(submessage: SubMessage<R>) -> Result<Self, GribError> {
let mut reader = submessage.9;
let sect5 = submessage.5.body;
let sect6 = submessage.6.body;
let sect7 = submessage.7.body;
let sect3_body = match submessage.3.body.body.as_ref() {
Some(SectionBody::Section3(b3)) => b3,
_ => return Err(GribError::InternalDataError),
};
let sect3_num_points = sect3_body.num_points() as usize;
Self::new(
sect3_num_points,
reader.read_sect_as_slice(sect5)?,
reader.read_sect_as_slice(sect6)?,
reader.read_sect_as_slice(sect7)?,
)
}
pub fn dispatch(
&self,
) -> Result<Grib2DecodedValues<'_, impl Iterator<Item = f32> + '_>, GribError> {
let decoder = match &self.sect5_param.payload.template {
DataRepresentationTemplate::_5_0(template) => {
Grib2ValueIterator::SigSTNS(simple::Simple(self, template).iter()?)
}
DataRepresentationTemplate::_5_2(template) => {
Grib2ValueIterator::SigSC(complex::Complex(self, template).iter()?)
}
DataRepresentationTemplate::_5_3(template) => {
Grib2ValueIterator::SigSSCI(complex::ComplexSpatial(self, template).iter()?)
}
#[cfg(feature = "jpeg2000-unpack-with-openjpeg")]
DataRepresentationTemplate::_5_40(template) => {
Grib2ValueIterator::SigSIm(jpeg2000::Jpeg2000(self, template).iter()?)
}
#[cfg(feature = "png-unpack-with-png-crate")]
DataRepresentationTemplate::_5_41(template) => {
Grib2ValueIterator::SigSNV(png::Png(self, template).iter()?)
}
#[cfg(feature = "ccsds-unpack-with-libaec")]
DataRepresentationTemplate::_5_42(template) => {
Grib2ValueIterator::SigSNV(ccsds::Ccsds(self, template).iter()?)
}
DataRepresentationTemplate::_5_200(template) => {
Grib2ValueIterator::SigI(run_length::RunLength(self, template).iter()?)
}
#[allow(unreachable_patterns)]
_ => {
return Err(GribError::DecodeError(DecodeError::NotSupported(
"GRIB2 code table 5.0 (data representation template number)",
self.sect5_param.payload.template_num,
)));
}
};
let decoder = BitmapDecodeIterator::new(
self.sect6_bytes[6..].iter(),
decoder,
self.num_points_total,
)?;
Ok(Grib2DecodedValues(decoder))
}
pub(crate) fn num_encoded_points(&self) -> usize {
self.sect5_param.payload.num_encoded_points as usize
}
pub(crate) fn sect7_payload(&self) -> &[u8] {
&self.sect7_bytes[5..]
}
pub fn section5(&self) -> &Section5 {
&self.sect5_param
}
}
pub(crate) fn orig_field_type_is_supported(orig_field_type: u8) -> Result<(), DecodeError> {
if orig_field_type != 0 {
return Err(DecodeError::NotSupported(
"GRIB2 code table 5.1 (type of original field values)",
orig_field_type.into(),
));
}
Ok(())
}
pub struct Grib2DecodedValues<'b, I>(BitmapDecodeIterator<std::slice::Iter<'b, u8>, I>);
impl<'a, I> Iterator for Grib2DecodedValues<'a, I>
where
I: Iterator<Item = f32>,
{
type Item = f32;
fn next(&mut self) -> Option<Self::Item> {
let Self(inner) = self;
inner.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
let Self(inner) = self;
inner.size_hint()
}
}
enum Grib2ValueIterator<'d> {
SigSTNS(SimplePackingDecoder<std::iter::Take<NBitwiseIterator<&'d [u8]>>>),
SigSC(SimplePackingDecoder<ComplexPackingDecoded<'d>>),
SigSSCI(
SimplePackingDecoder<
complex::SpatialDifferencingDecodeIterator<ComplexPackingDecoded<'d>, IntoIter<i32>>,
>,
),
#[allow(dead_code)]
SigSI(SimplePackingDecoder<IntoIter<i32>>),
#[cfg(feature = "jpeg2000-unpack-with-openjpeg")]
SigSIm(SimplePackingDecoder<self::jpeg2000::ImageIntoIter>),
#[allow(dead_code)]
SigSNV(SimplePackingDecoder<NBitwiseIterator<Vec<u8>>>),
SigI(IntoIter<f32>),
}
impl<'d> Iterator for Grib2ValueIterator<'d> {
type Item = f32;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::SigSTNS(inner) => inner.next(),
Self::SigSC(inner) => inner.next(),
Self::SigSSCI(inner) => inner.next(),
Self::SigSI(inner) => inner.next(),
#[cfg(feature = "jpeg2000-unpack-with-openjpeg")]
Self::SigSIm(inner) => inner.next(),
Self::SigSNV(inner) => inner.next(),
Self::SigI(inner) => inner.next(),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
Self::SigSTNS(inner) => inner.size_hint(),
Self::SigSC(inner) => inner.size_hint(),
Self::SigSSCI(inner) => inner.size_hint(),
Self::SigSI(inner) => inner.size_hint(),
#[cfg(feature = "jpeg2000-unpack-with-openjpeg")]
Self::SigSIm(inner) => inner.size_hint(),
Self::SigSNV(inner) => inner.size_hint(),
Self::SigI(inner) => inner.size_hint(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum DecodeError {
NotSupported(&'static str, u16),
LengthMismatch,
UnclassifiedError(String),
}
impl From<String> for DecodeError {
fn from(value: String) -> Self {
Self::UnclassifiedError(value)
}
}
impl From<&str> for DecodeError {
fn from(value: &str) -> Self {
Self::UnclassifiedError(value.to_owned())
}
}
pub(crate) trait Grib2GpvUnpack {
type Iter<'a>: Iterator<Item = f32>
where
Self: 'a;
fn iter<'a>(&'a self) -> Result<Self::Iter<'a>, DecodeError>;
}
mod bitmap;
#[cfg(feature = "ccsds-unpack-with-libaec")]
mod ccsds;
mod complex;
mod helpers;
#[cfg(feature = "jpeg2000-unpack-with-openjpeg")]
mod jpeg2000;
#[cfg(feature = "png-unpack-with-png-crate")]
mod png;
mod run_length;
mod simple;
mod stream;