Initial attempt at no_std
This commit is contained in:
parent
e39bec8725
commit
5469530c64
8 changed files with 83 additions and 27 deletions
|
@ -16,7 +16,9 @@ exclude = [
|
|||
]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["std"]
|
||||
alloc = [] # provides access to `Vec` without enabling `std` mode
|
||||
std = [] # std mode (enabled by default) - provides access to `std::io`, `Error` and `Vec`
|
||||
reference = [] # follows reference encoder implementation precisely, but may be slightly slower
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
use alloc::{vec, vec::Vec};
|
||||
#[cfg(feature = "std")]
|
||||
use std::io::Read;
|
||||
|
||||
// TODO: can be removed once https://github.com/rust-lang/rust/issues/74985 is stable
|
||||
|
@ -111,6 +114,7 @@ pub fn qoi_decode_to_buf(buf: impl AsMut<[u8]>, data: impl AsRef<[u8]>) -> Resul
|
|||
Ok(*decoder.header())
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[inline]
|
||||
pub fn qoi_decode_to_vec(data: impl AsRef<[u8]>) -> Result<(Header, Vec<u8>)> {
|
||||
let mut decoder = QoiDecoder::new(&data)?;
|
||||
|
@ -177,6 +181,7 @@ impl<'a> QoiDecoder<'a> {
|
|||
Ok(size)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
#[inline]
|
||||
pub fn decode_to_vec(&mut self) -> Result<Vec<u8>> {
|
||||
let mut out = vec![0; self.header.n_pixels() * self.channels.as_u8() as usize];
|
||||
|
@ -184,6 +189,7 @@ impl<'a> QoiDecoder<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std"))]
|
||||
#[inline]
|
||||
fn qoi_decode_impl_stream<R: Read, const N: usize, const RGBA: bool>(
|
||||
data: &mut R, out: &mut [u8],
|
||||
|
@ -253,6 +259,7 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[inline]
|
||||
fn qoi_decode_impl_stream_all<R: Read>(
|
||||
data: &mut R, out: &mut [u8], channels: u8, src_channels: u8,
|
||||
|
@ -269,12 +276,14 @@ fn qoi_decode_impl_stream_all<R: Read>(
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub struct QoiStreamDecoder<R> {
|
||||
reader: R,
|
||||
header: Header,
|
||||
channels: Channels,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<R: Read> QoiStreamDecoder<R> {
|
||||
#[inline]
|
||||
pub fn new(mut reader: R) -> Result<Self> {
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use std::convert::TryFrom;
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
use alloc::{vec, vec::Vec};
|
||||
use core::convert::TryFrom;
|
||||
#[cfg(feature = "std")]
|
||||
use std::io::Write;
|
||||
|
||||
use crate::consts::{QOI_HEADER_SIZE, QOI_OP_INDEX, QOI_OP_RUN, QOI_PADDING, QOI_PADDING_SIZE};
|
||||
|
@ -6,7 +9,9 @@ use crate::error::{Error, Result};
|
|||
use crate::header::Header;
|
||||
use crate::pixel::{Pixel, SupportedChannels};
|
||||
use crate::types::{Channels, ColorSpace};
|
||||
use crate::utils::{unlikely, BytesMut, GenericWriter, Writer};
|
||||
#[cfg(feature = "std")]
|
||||
use crate::utils::GenericWriter;
|
||||
use crate::utils::{cold, unlikely, BytesMut, Writer};
|
||||
|
||||
#[allow(clippy::cast_possible_truncation, unused_assignments)]
|
||||
fn qoi_encode_impl<W: Writer, const N: usize>(mut buf: W, data: &[u8]) -> Result<usize>
|
||||
|
@ -89,6 +94,7 @@ pub fn qoi_encode_to_buf(
|
|||
QoiEncoder::new(&data, width, height)?.encode_to_buf(buf)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
#[inline]
|
||||
pub fn qoi_encode_to_vec(data: impl AsRef<[u8]>, width: u32, height: u32) -> Result<Vec<u8>> {
|
||||
QoiEncoder::new(&data, width, height)?.encode_to_vec()
|
||||
|
@ -149,6 +155,7 @@ impl<'a> QoiEncoder<'a> {
|
|||
Ok(QOI_HEADER_SIZE + n_written)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
#[inline]
|
||||
pub fn encode_to_vec(&self) -> Result<Vec<u8>> {
|
||||
let mut out = vec![0_u8; self.encoded_size_limit()];
|
||||
|
@ -157,6 +164,7 @@ impl<'a> QoiEncoder<'a> {
|
|||
Ok(out)
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[inline]
|
||||
pub fn encode_to_stream<W: Write>(&self, writer: &mut W) -> Result<usize> {
|
||||
writer.write_all(&self.header.encode())?;
|
||||
|
|
59
src/error.rs
59
src/error.rs
|
@ -1,27 +1,47 @@
|
|||
use std::convert::Infallible;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt::{self, Display};
|
||||
use std::io;
|
||||
use std::result::Result as StdResult;
|
||||
use core::convert::Infallible;
|
||||
use core::fmt::{self, Display};
|
||||
|
||||
use crate::consts::{QOI_MAGIC, QOI_PIXELS_MAX};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
InvalidChannels { channels: u8 },
|
||||
EmptyImage { width: u32, height: u32 },
|
||||
ImageTooLarge { width: u32, height: u32 },
|
||||
InvalidImageLength { size: usize, width: u32, height: u32 },
|
||||
InputBufferTooSmall { size: usize, required: usize },
|
||||
OutputBufferTooSmall { size: usize, required: usize },
|
||||
InvalidMagic { magic: u32 },
|
||||
InvalidChannels {
|
||||
channels: u8,
|
||||
},
|
||||
EmptyImage {
|
||||
width: u32,
|
||||
height: u32,
|
||||
},
|
||||
ImageTooLarge {
|
||||
width: u32,
|
||||
height: u32,
|
||||
},
|
||||
InvalidImageLength {
|
||||
size: usize,
|
||||
width: u32,
|
||||
height: u32,
|
||||
},
|
||||
InputBufferTooSmall {
|
||||
size: usize,
|
||||
required: usize,
|
||||
},
|
||||
OutputBufferTooSmall {
|
||||
size: usize,
|
||||
required: usize,
|
||||
},
|
||||
InvalidMagic {
|
||||
magic: u32,
|
||||
},
|
||||
UnexpectedBufferEnd,
|
||||
InvalidColorSpace { colorspace: u8 },
|
||||
InvalidColorSpace {
|
||||
colorspace: u8,
|
||||
},
|
||||
InvalidPadding,
|
||||
IoError(io::Error),
|
||||
#[cfg(feature = "std")]
|
||||
IoError(std::io::Error),
|
||||
}
|
||||
|
||||
pub type Result<T> = StdResult<T, Error>;
|
||||
pub type Result<T> = core::result::Result<T, Error>;
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
@ -57,6 +77,7 @@ impl Display for Error {
|
|||
Self::InvalidPadding => {
|
||||
write!(f, "invalid padding (stream end marker)")
|
||||
}
|
||||
#[cfg(feature = "std")]
|
||||
Self::IoError(ref err) => {
|
||||
write!(f, "i/o error: {}", err)
|
||||
}
|
||||
|
@ -64,7 +85,8 @@ impl Display for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl StdError for Error {}
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
impl From<Infallible> for Error {
|
||||
fn from(_: Infallible) -> Self {
|
||||
|
@ -72,8 +94,9 @@ impl From<Infallible> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(err: io::Error) -> Self {
|
||||
#[cfg(feature = "std")]
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
Self::IoError(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::convert::TryInto;
|
||||
use core::convert::TryInto;
|
||||
|
||||
use bytemuck::cast_slice;
|
||||
|
||||
|
|
18
src/lib.rs
18
src/lib.rs
|
@ -8,6 +8,11 @@
|
|||
clippy::module_name_repetitions,
|
||||
clippy::cargo_common_metadata
|
||||
)]
|
||||
#![cfg_attr(not(any(feature = "std", test)), no_std)]
|
||||
#[cfg(all(feature = "alloc", not(any(feature = "std", test))))]
|
||||
extern crate alloc;
|
||||
#[cfg(any(feature = "std", test))]
|
||||
extern crate std as alloc;
|
||||
|
||||
mod decode;
|
||||
mod encode;
|
||||
|
@ -20,10 +25,15 @@ mod utils;
|
|||
#[doc(hidden)]
|
||||
pub mod consts;
|
||||
|
||||
pub use crate::decode::{
|
||||
qoi_decode_header, qoi_decode_to_buf, qoi_decode_to_vec, QoiDecoder, QoiStreamDecoder,
|
||||
};
|
||||
pub use crate::encode::{encoded_size_limit, qoi_encode_to_buf, qoi_encode_to_vec, QoiEncoder};
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub use crate::decode::qoi_decode_to_vec;
|
||||
#[cfg(feature = "std")]
|
||||
pub use crate::decode::QoiStreamDecoder;
|
||||
pub use crate::decode::{qoi_decode_header, qoi_decode_to_buf, QoiDecoder};
|
||||
|
||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||
pub use crate::encode::qoi_encode_to_vec;
|
||||
pub use crate::encode::{encoded_size_limit, qoi_encode_to_buf, QoiEncoder};
|
||||
pub use crate::error::{Error, Result};
|
||||
pub use crate::header::Header;
|
||||
pub use crate::types::{Channels, ColorSpace};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::convert::TryFrom;
|
||||
use core::convert::TryFrom;
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::utils::unlikely;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#[cfg(feature = "std")]
|
||||
use std::io::Write;
|
||||
|
||||
use crate::error::Result;
|
||||
|
@ -29,17 +30,20 @@ pub trait Writer: Sized {
|
|||
fn capacity(&self) -> usize;
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub struct GenericWriter<W> {
|
||||
writer: W,
|
||||
n_written: usize,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<W: Write> GenericWriter<W> {
|
||||
pub fn new(writer: W) -> Self {
|
||||
Self { writer, n_written: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<W: Write> Writer for GenericWriter<W> {
|
||||
fn write_one(mut self, v: u8) -> Result<Self> {
|
||||
self.n_written += 1;
|
||||
|
|
Loading…
Reference in a new issue