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