use alloc::vec::Vec;
#[allow(unused_imports)]
use whereat::at;
use super::api::{DecodeConfig, DecodeError, DecodeResult, ImageInfo, WebPDecoder};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum StreamStatus {
NeedMoreData,
HeaderReady,
Complete,
}
pub struct StreamingDecoder {
buf: Vec<u8>,
riff_size: Option<u32>,
header_parsed: bool,
config: DecodeConfig,
}
impl StreamingDecoder {
#[must_use]
pub fn new() -> Self {
Self {
buf: Vec::new(),
riff_size: None,
header_parsed: false,
config: DecodeConfig::default(),
}
}
#[must_use]
pub fn with_config(config: DecodeConfig) -> Self {
Self {
buf: Vec::new(),
riff_size: None,
header_parsed: false,
config,
}
}
pub fn append(&mut self, data: &[u8]) -> Result<StreamStatus, whereat::At<DecodeError>> {
self.buf.extend_from_slice(data);
if self.riff_size.is_none() && self.buf.len() >= 12 {
if &self.buf[0..4] != b"RIFF" {
return Err(at!(DecodeError::RiffSignatureInvalid(
self.buf[0..4].try_into().unwrap(),
)));
}
let size = u32::from_le_bytes(self.buf[4..8].try_into().unwrap());
if &self.buf[8..12] != b"WEBP" {
return Err(at!(DecodeError::WebpSignatureInvalid(
self.buf[8..12].try_into().unwrap(),
)));
}
self.riff_size = Some(size);
}
if !self.header_parsed && self.buf.len() >= 30 {
if WebPDecoder::new(&self.buf).is_ok() {
self.header_parsed = true;
}
}
if let Some(riff_size) = self.riff_size {
let total = riff_size as usize + 8; if self.buf.len() >= total {
return Ok(StreamStatus::Complete);
}
}
if self.header_parsed {
Ok(StreamStatus::HeaderReady)
} else {
Ok(StreamStatus::NeedMoreData)
}
}
pub fn info(&self) -> DecodeResult<ImageInfo> {
if !self.header_parsed {
return Err(whereat::at!(DecodeError::InvalidParameter(
alloc::string::String::from("headers not yet available"),
)));
}
ImageInfo::from_webp(&self.buf)
}
#[must_use]
pub fn bytes_buffered(&self) -> usize {
self.buf.len()
}
#[must_use]
pub fn total_size(&self) -> Option<usize> {
self.riff_size.map(|s| s as usize + 8)
}
#[must_use]
pub fn is_complete(&self) -> bool {
self.total_size()
.is_some_and(|total| self.buf.len() >= total)
}
pub fn finish_rgba(self) -> DecodeResult<(Vec<u8>, u32, u32)> {
self.ensure_complete()?;
super::api::DecodeRequest::new(&self.config, &self.buf).decode_rgba()
}
pub fn finish_rgb(self) -> DecodeResult<(Vec<u8>, u32, u32)> {
self.ensure_complete()?;
super::api::DecodeRequest::new(&self.config, &self.buf).decode_rgb()
}
pub fn finish_rgba_into(self, output: &mut [u8]) -> DecodeResult<(u32, u32)> {
self.ensure_complete()?;
super::api::DecodeRequest::new(&self.config, &self.buf).decode_rgba_into(output)
}
#[must_use]
pub fn into_inner(self) -> Vec<u8> {
self.buf
}
fn ensure_complete(&self) -> Result<(), whereat::At<DecodeError>> {
if !self.is_complete() {
return Err(at!(DecodeError::InvalidParameter(
alloc::string::String::from("data incomplete"),
)));
}
Ok(())
}
}
impl Default for StreamingDecoder {
fn default() -> Self {
Self::new()
}
}