use std::{io, marker::PhantomData};
use libflate::zlib::Decoder as ZlibDecoder;
use crate::{
low::v7400::ArrayAttributeEncoding,
pull_parser::{error::DataError, Result},
};
#[derive(Debug)]
pub(crate) enum AttributeStreamDecoder<R> {
Direct(R),
Zlib(ZlibDecoder<R>),
}
impl<R: io::Read> AttributeStreamDecoder<R> {
pub(crate) fn create(encoding: ArrayAttributeEncoding, reader: R) -> Result<Self> {
match encoding {
ArrayAttributeEncoding::Direct => Ok(AttributeStreamDecoder::Direct(reader)),
ArrayAttributeEncoding::Zlib => Ok(AttributeStreamDecoder::Zlib(
ZlibDecoder::new(reader)
.map_err(|e| DataError::BrokenCompression(encoding.into(), e.into()))?,
)),
}
}
}
impl<R: io::Read> io::Read for AttributeStreamDecoder<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
AttributeStreamDecoder::Direct(reader) => reader.read(buf),
AttributeStreamDecoder::Zlib(reader) => reader.read(buf),
}
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct ArrayAttributeValues<R, E> {
reader: R,
rest_elements: u32,
has_error: bool,
_element_type: PhantomData<E>,
}
impl<R, E> ArrayAttributeValues<R, E>
where
R: io::Read,
{
#[inline]
#[must_use]
pub(crate) fn new(reader: R, total_elements: u32) -> Self {
Self {
reader,
rest_elements: total_elements,
has_error: false,
_element_type: PhantomData,
}
}
#[inline]
#[must_use]
pub(crate) fn has_error(&self) -> bool {
self.has_error
}
}
macro_rules! impl_array_attr_values {
($ty_elem:ty) => {
impl<R: io::Read> Iterator for ArrayAttributeValues<R, $ty_elem> {
type Item = Result<$ty_elem>;
fn next(&mut self) -> Option<Self::Item> {
if self.rest_elements == 0 {
return None;
}
let mut buf = [0_u8; std::mem::size_of::<$ty_elem>()];
match self.reader.read_exact(&mut buf) {
Ok(()) => {
let v = <$ty_elem>::from_le_bytes(buf);
self.rest_elements = self
.rest_elements
.checked_sub(1)
.expect("This should be executed only when there are rest elements");
Some(Ok(v))
}
Err(e) => {
self.has_error = true;
Some(Err(e.into()))
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.rest_elements as usize))
}
}
impl<R: io::Read> std::iter::FusedIterator for ArrayAttributeValues<R, $ty_elem> {}
};
}
impl_array_attr_values! { i32 }
impl_array_attr_values! { i64 }
impl_array_attr_values! { f32 }
impl_array_attr_values! { f64 }
#[derive(Debug, Clone, Copy)]
pub(crate) struct BooleanArrayAttributeValues<R> {
reader: R,
rest_elements: u32,
has_error: bool,
has_incorrect_boolean_value: bool,
}
impl<R: io::Read> BooleanArrayAttributeValues<R> {
#[inline]
#[must_use]
pub(crate) fn new(reader: R, total_elements: u32) -> Self {
Self {
reader,
rest_elements: total_elements,
has_error: false,
has_incorrect_boolean_value: false,
}
}
#[inline]
#[must_use]
pub(crate) fn has_incorrect_boolean_value(&self) -> bool {
self.has_incorrect_boolean_value
}
#[inline]
#[must_use]
pub(crate) fn has_error(&self) -> bool {
self.has_error
}
}
impl<R: io::Read> Iterator for BooleanArrayAttributeValues<R> {
type Item = Result<bool>;
fn next(&mut self) -> Option<Self::Item> {
if self.rest_elements == 0 {
return None;
}
let mut raw = 0_u8;
match self.reader.read_exact(std::slice::from_mut(&mut raw)) {
Ok(()) => {
self.rest_elements = self
.rest_elements
.checked_sub(1)
.expect("This should be executed only when there are rest elements");
if raw != b'T' && raw != b'Y' {
self.has_incorrect_boolean_value = true;
}
let v = (raw & 1) != 0;
Some(Ok(v))
}
Err(e) => {
self.has_error = true;
Some(Err(e.into()))
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.rest_elements as usize))
}
}
impl<R: io::Read> std::iter::FusedIterator for BooleanArrayAttributeValues<R> {}