diff --git a/src/decode.rs b/src/decode.rs index f0721bf..0049a18 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -125,68 +125,6 @@ pub fn decode_header(data: impl AsRef<[u8]>) -> Result
{ Header::decode(data) } -#[derive(Clone)] -pub struct Decoder<'a> { - data: &'a [u8], - header: Header, - channels: Channels, -} - -impl<'a> Decoder<'a> { - #[inline] - pub fn new(data: &'a (impl AsRef<[u8]> + ?Sized)) -> Result { - let data = data.as_ref(); - let header = Header::decode(data)?; - let data = &data[QOI_HEADER_SIZE..]; // can't panic - Ok(Self { data, header, channels: header.channels }) - } - - #[inline] - pub const fn with_channels(mut self, channels: Channels) -> Self { - self.channels = channels; - self - } - - #[inline] - pub const fn channels(&self) -> Channels { - self.channels - } - - #[inline] - pub const fn header(&self) -> &Header { - &self.header - } - - #[inline] - pub const fn data(self) -> &'a [u8] { - self.data - } - - #[inline] - pub fn decode_to_buf(&mut self, mut buf: impl AsMut<[u8]>) -> Result { - let buf = buf.as_mut(); - let size = self.header.n_pixels() * self.channels.as_u8() as usize; - if unlikely(buf.len() < size) { - return Err(Error::OutputBufferTooSmall { size: buf.len(), required: size }); - } - let n_read = decode_impl_slice_all( - self.data, - buf, - self.channels.as_u8(), - self.header.channels.as_u8(), - )?; - self.data = &self.data[n_read..]; // can't panic - Ok(size) - } - - #[cfg(any(feature = "std", feature = "alloc"))] - #[inline] - pub fn decode_to_vec(&mut self) -> Result> { - let mut out = vec![0; self.header.n_pixels() * self.channels.as_u8() as usize]; - self.decode_to_buf(&mut out).map(|_| out) - } -} - #[cfg(any(feature = "std"))] #[inline] fn decode_impl_stream( @@ -274,20 +212,98 @@ fn decode_impl_stream_all( } } +#[doc(hidden)] +pub trait Reader: Sized { + fn decode_header(&mut self) -> Result
; + fn decode_image(&mut self, out: &mut [u8], channels: u8, src_channels: u8) -> Result<()>; +} + +struct Bytes<'a>(&'a [u8]); + +impl<'a> Bytes<'a> { + #[inline] + pub const fn new(buf: &'a [u8]) -> Self { + Self(buf) + } + + #[inline] + pub const fn as_slice(&self) -> &[u8] { + self.0 + } +} + +impl<'a> Reader for Bytes<'a> { + #[inline] + fn decode_header(&mut self) -> Result
{ + let header = Header::decode(self.0)?; + self.0 = &self.0[QOI_HEADER_SIZE..]; // can't panic + Ok(header) + } + + #[inline] + fn decode_image(&mut self, out: &mut [u8], channels: u8, src_channels: u8) -> Result<()> { + let n_read = decode_impl_slice_all(self.0, out, channels, src_channels)?; + self.0 = &self.0[n_read..]; + Ok(()) + } +} + #[cfg(feature = "std")] -pub struct StreamDecoder { +impl Reader for R { + #[inline] + fn decode_header(&mut self) -> Result
{ + let mut b = [0; QOI_HEADER_SIZE]; + self.read_exact(&mut b)?; + Header::decode(b) + } + + #[inline] + fn decode_image(&mut self, out: &mut [u8], channels: u8, src_channels: u8) -> Result<()> { + decode_impl_stream_all(self, out, channels, src_channels) + } +} + +#[derive(Clone)] +pub struct Decoder { reader: R, header: Header, channels: Channels, } -#[cfg(feature = "std")] -impl StreamDecoder { +impl<'a> Decoder> { #[inline] - pub fn new(mut reader: R) -> Result { - let mut b = [0; QOI_HEADER_SIZE]; - reader.read_exact(&mut b)?; - let header = Header::decode(b)?; + pub fn new(data: &'a (impl AsRef<[u8]> + ?Sized)) -> Result { + Self::new_impl(Bytes::new(data.as_ref())) + } + + #[inline] + pub const fn data(&self) -> &[u8] { + self.reader.as_slice() + } +} + +#[cfg(feature = "std")] +impl Decoder { + #[inline] + pub fn from_stream(reader: R) -> Result { + Self::new_impl(reader) + } + + #[inline] + pub fn reader(&self) -> &R { + &self.reader + } + + #[inline] + pub fn into_reader(self) -> R { + self.reader + } +} + +impl Decoder { + #[inline] + fn new_impl(mut reader: R) -> Result { + let header = reader.decode_header()?; Ok(Self { reader, header, channels: header.channels }) } @@ -306,16 +322,6 @@ impl StreamDecoder { &self.header } - #[inline] - pub fn reader(&self) -> &R { - &self.reader - } - - #[inline] - pub fn into_reader(self) -> R { - self.reader - } - #[inline] pub fn decode_to_buf(&mut self, mut buf: impl AsMut<[u8]>) -> Result { let buf = buf.as_mut(); @@ -323,15 +329,11 @@ impl StreamDecoder { if unlikely(buf.len() < size) { return Err(Error::OutputBufferTooSmall { size: buf.len(), required: size }); } - decode_impl_stream_all( - &mut self.reader, - buf, - self.channels.as_u8(), - self.header.channels.as_u8(), - )?; + self.reader.decode_image(buf, self.channels.as_u8(), self.header.channels.as_u8())?; Ok(size) } + #[cfg(any(feature = "std", feature = "alloc"))] #[inline] pub fn decode_to_vec(&mut self) -> Result> { let mut out = vec![0; self.header.n_pixels() * self.channels.as_u8() as usize]; diff --git a/src/lib.rs b/src/lib.rs index 2bb3e17..91d8c55 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,13 +27,12 @@ pub mod consts; #[cfg(any(feature = "alloc", feature = "std"))] pub use crate::decode::decode_to_vec; -#[cfg(feature = "std")] -pub use crate::decode::StreamDecoder; pub use crate::decode::{decode_header, decode_to_buf, Decoder}; #[cfg(any(feature = "alloc", feature = "std"))] pub use crate::encode::encode_to_vec; pub use crate::encode::{encode_size_limit, encode_to_buf, Encoder}; + pub use crate::error::{Error, Result}; pub use crate::header::Header; pub use crate::types::{Channels, ColorSpace};