Skip to content

Commit

Permalink
lib: add support for no_std builds
Browse files Browse the repository at this point in the history
Introduce a new, default `std` feature to the library, and conditionally
use structures and traits from `no_std` compatible libraries.

Existing `std` users can continue using the library with no changes.
`no_std` users can import the library using `default_features = false`.
  • Loading branch information
rmsyn committed Feb 14, 2023
1 parent 0c11c3e commit b10f88a
Show file tree
Hide file tree
Showing 22 changed files with 389 additions and 89 deletions.
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ coveralls = {repository = "sile/libflate"}
[dependencies]
adler32 = "1"
crc32fast = "1.1.1"
libflate_lz77 = { path = "libflate_lz77", version = "1.1" }
libflate_lz77 = { path = "libflate_lz77", version = "1.1", default_features = false }
core2 = { version = "0.4", default_features = false, features = ["alloc"], optional = true }

[features]
no_std = ["libflate_lz77/no_std", "core2"]

[dev-dependencies]
clap = "2"
Expand Down
14 changes: 14 additions & 0 deletions examples/flate.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
extern crate clap;
extern crate libflate;

#[cfg(not(feature = "no_std"))]
use clap::App;
#[cfg(not(feature = "no_std"))]
use clap::Arg;
#[cfg(not(feature = "no_std"))]
use clap::SubCommand;
#[cfg(not(feature = "no_std"))]
use libflate::gzip;
#[cfg(not(feature = "no_std"))]
use libflate::zlib;
#[cfg(not(feature = "no_std"))]
use std::fs;
#[cfg(not(feature = "no_std"))]
use std::io;
#[cfg(not(feature = "no_std"))]
use std::io::Read;
#[cfg(not(feature = "no_std"))]
use std::io::Write;
#[cfg(not(feature = "no_std"))]
use std::process;

#[cfg(feature = "no_std")]
fn main() {}

#[cfg(not(feature = "no_std"))]
fn main() {
let matches = App::new("deflate")
.arg(
Expand Down
5 changes: 5 additions & 0 deletions libflate_lz77/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ coveralls = {repository = "sile/libflate"}

[dependencies]
rle-decode-fast = "1.0.0"
core2 = { version = "0.4", default-features = false, features = ["alloc"], optional = true }
hashbrown = { version = "0.13", optional = true }

[dev-dependencies]
libflate = { path = "../", version = "1" }

[features]
no_std = ["core2", "hashbrown"]
10 changes: 8 additions & 2 deletions libflate_lz77/src/default.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
use std::cmp;
use std::collections::HashMap;
#[cfg(feature = "no_std")]
use alloc::vec::Vec;
#[cfg(feature = "no_std")]
use core::cmp;
#[cfg(feature = "no_std")]
use hashbrown::HashMap;
#[cfg(not(feature = "no_std"))]
use std::{cmp, collections::HashMap};

use super::Code;
use super::Lz77Encode;
Expand Down
34 changes: 25 additions & 9 deletions libflate_lz77/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,19 @@
//!
//! LZ77 is a compression algorithm used in [DEFLATE](https://tools.ietf.org/html/rfc1951).
#![warn(missing_docs)]
#![cfg_attr(no_std, feature = "no_std")]

#[cfg(feature = "no_std")]
extern crate alloc;

pub use self::default::{DefaultLz77Encoder, DefaultLz77EncoderBuilder};
#[cfg(feature = "no_std")]
use alloc::vec::Vec;
#[cfg(feature = "no_std")]
use core2::io;
use rle_decode_fast::rle_decode;
#[cfg(not(feature = "no_std"))]
use std::io;

mod default;

Expand Down Expand Up @@ -157,7 +168,7 @@ impl Lz77Decoder {
///
/// The decoded bytes are appended to the buffer of [`Lz77Decoder`].
#[inline]
pub fn decode(&mut self, code: Code) -> std::io::Result<()> {
pub fn decode(&mut self, code: Code) -> io::Result<()> {
match code {
Code::Literal(b) => {
self.buffer.push(b);
Expand All @@ -167,13 +178,16 @@ impl Lz77Decoder {
backward_distance,
} => {
if self.buffer.len() < backward_distance as usize {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
return Err(io::Error::new(
io::ErrorKind::InvalidData,
#[cfg(not(feature = "no_std"))]
format!(
"Too long backword reference: buffer.len={}, distance={}",
self.buffer.len(),
backward_distance
),
#[cfg(feature = "no_std")]
"Too long backword reference",
));
}
rle_decode(
Expand All @@ -187,10 +201,7 @@ impl Lz77Decoder {
}

/// Appends the bytes read from `reader` to the buffer of [`Lz77Decoder`].
pub fn extend_from_reader<R: std::io::Read>(
&mut self,
mut reader: R,
) -> std::io::Result<usize> {
pub fn extend_from_reader<R: io::Read>(&mut self, mut reader: R) -> io::Result<usize> {
reader.read_to_end(&mut self.buffer)
}

Expand Down Expand Up @@ -227,8 +238,8 @@ impl Lz77Decoder {
}
}

impl std::io::Read for Lz77Decoder {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
impl io::Read for Lz77Decoder {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let copy_size = std::cmp::min(buf.len(), self.buffer.len() - self.offset);
buf[..copy_size].copy_from_slice(&self.buffer[self.offset..][..copy_size]);
self.offset += copy_size;
Expand All @@ -240,6 +251,11 @@ impl std::io::Read for Lz77Decoder {
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "no_std")]
use alloc::vec::Vec;
#[cfg(feature = "no_std")]
use core2::io::Read as _;
#[cfg(not(feature = "no_std"))]
use std::io::Read as _;

#[test]
Expand Down
6 changes: 6 additions & 0 deletions src/bit.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#[cfg(feature = "no_std")]
use core2::io;
#[cfg(not(feature = "no_std"))]
use std::io;

#[derive(Debug)]
Expand Down Expand Up @@ -176,6 +179,9 @@ pub(crate) struct BitReaderState {
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "no_std")]
use core2::io;
#[cfg(not(feature = "no_std"))]
use std::io;

#[test]
Expand Down
3 changes: 3 additions & 0 deletions src/checksum.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use adler32::RollingAdler32;
#[cfg(feature = "no_std")]
use core::fmt;
#[cfg(not(feature = "no_std"))]
use std::fmt;

pub struct Adler32(RollingAdler32);
Expand Down
19 changes: 17 additions & 2 deletions src/deflate/decode.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use super::symbol;
use crate::bit;
use crate::lz77;
use std::io;
use std::io::Read;
#[cfg(feature = "no_std")]
use core2::io::{self, Read};
#[cfg(not(feature = "no_std"))]
use std::io::{self, Read};

/// DEFLATE decoder.
#[derive(Debug)]
Expand All @@ -21,6 +23,9 @@ where
///
/// # Examples
/// ```
/// #[cfg(feature = "no_std")]
/// use core2::io::{Cursor, Read};
/// #[cfg(not(feature = "no_std"))]
/// use std::io::{Cursor, Read};
/// use libflate::deflate::Decoder;
///
Expand Down Expand Up @@ -53,6 +58,9 @@ where
///
/// # Examples
/// ```
/// #[cfg(feature = "no_std")]
/// use core2::io::Cursor;
/// #[cfg(not(feature = "no_std"))]
/// use std::io::Cursor;
/// use libflate::deflate::Decoder;
///
Expand Down Expand Up @@ -90,7 +98,10 @@ where
if used != len.into() {
Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
#[cfg(not(feature = "no_std"))]
format!("The reader has incorrect length: expected {len}, read {used}"),
#[cfg(feature = "no_std")]
"The reader has incorrect length",
))
} else {
Ok(())
Expand Down Expand Up @@ -155,8 +166,10 @@ where

#[cfg(test)]
mod tests {
#[cfg(not(feature = "no_std"))]
use super::*;
use crate::deflate::symbol::{DynamicHuffmanCodec, HuffmanCodec};
#[cfg(not(feature = "no_std"))]
use std::io;

#[test]
Expand All @@ -177,6 +190,7 @@ mod tests {
}

#[test]
#[cfg(not(feature = "no_std"))]
fn it_works() {
let input = [
180, 253, 73, 143, 28, 201, 150, 46, 8, 254, 150, 184, 139, 75, 18, 69, 247, 32, 157,
Expand All @@ -198,6 +212,7 @@ mod tests {
}

#[test]
#[cfg(not(feature = "no_std"))]
fn test_issue_64() {
let input = b"\x04\x04\x04\x05:\x1az*\xfc\x06\x01\x90\x01\x06\x01";
let mut decoder = Decoder::new(&input[..]);
Expand Down
26 changes: 21 additions & 5 deletions src/deflate/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ use super::BlockType;
use crate::bit;
use crate::finish::{Complete, Finish};
use crate::lz77;
use std::cmp;
use std::io;
#[cfg(feature = "no_std")]
use core::cmp;
#[cfg(feature = "no_std")]
use core2::io;
#[cfg(not(feature = "no_std"))]
use std::{cmp, io};

/// The default size of a DEFLATE block.
pub const DEFAULT_BLOCK_SIZE: usize = 1024 * 1024;
Expand Down Expand Up @@ -142,11 +146,14 @@ where
///
/// # Examples
/// ```
/// #[cfg(feature = "no_std")]
/// use core2::io::Write;
/// #[cfg(not(feature = "no_std"))]
/// use std::io::Write;
/// use libflate::deflate::Encoder;
///
/// let mut encoder = Encoder::new(Vec::new());
/// encoder.write_all(b"Hello World!").unwrap();
/// encoder.write_all(b"Hello World!".as_ref()).unwrap();
///
/// assert_eq!(encoder.finish().into_result().unwrap(),
/// [5, 192, 49, 13, 0, 0, 8, 3, 65, 43, 224, 6, 7, 24, 128, 237,
Expand All @@ -167,12 +174,15 @@ where
///
/// # Examples
/// ```
/// #[cfg(feature = "no_std")]
/// use core2::io::Write;
/// #[cfg(not(feature = "no_std"))]
/// use std::io::Write;
/// use libflate::deflate::{Encoder, EncodeOptions};
///
/// let options = EncodeOptions::new().no_compression();
/// let mut encoder = Encoder::with_options(Vec::new(), options);
/// encoder.write_all(b"Hello World!").unwrap();
/// encoder.write_all(b"Hello World!".as_ref()).unwrap();
///
/// assert_eq!(encoder.finish().into_result().unwrap(),
/// [1, 12, 0, 243, 255, 72, 101, 108, 108, 111, 32, 87, 111,
Expand All @@ -189,11 +199,14 @@ where
///
/// # Examples
/// ```
/// #[cfg(feature = "no_std")]
/// use core2::io::Write;
/// #[cfg(not(feature = "no_std"))]
/// use std::io::Write;
/// use libflate::deflate::Encoder;
///
/// let mut encoder = Encoder::new(Vec::new());
/// encoder.write_all(b"Hello World!").unwrap();
/// encoder.write_all(b"Hello World!".as_ref()).unwrap();
///
/// assert_eq!(encoder.finish().into_result().unwrap(),
/// [5, 192, 49, 13, 0, 0, 8, 3, 65, 43, 224, 6, 7, 24, 128, 237,
Expand Down Expand Up @@ -428,6 +441,9 @@ where
mod tests {
use super::super::Decoder;
use super::*;
#[cfg(feature = "no_std")]
use core2::io::{Read as _, Write as _};
#[cfg(not(feature = "no_std"))]
use std::io::{Read as _, Write as _};

#[test]
Expand Down
10 changes: 8 additions & 2 deletions src/deflate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
//!
//! # Examples
//! ```
//! use std::io::{self, Read};
//! #[cfg(feature = "no_std")]
//! use core2::io::{Read, Write};
//! #[cfg(not(feature = "no_std"))]
//! use std::io::{Read, Write};
//! use libflate::deflate::{Encoder, Decoder};
//!
//! // Encoding
//! let mut encoder = Encoder::new(Vec::new());
//! io::copy(&mut &b"Hello World!"[..], &mut encoder).unwrap();
//! encoder.write_all(b"Hello World!".as_ref()).unwrap();
//! let encoded_data = encoder.finish().into_result().unwrap();
//!
//! // Decoding
Expand Down Expand Up @@ -42,6 +45,9 @@ enum BlockType {
mod tests {
use super::*;
use crate::lz77;
#[cfg(feature = "no_std")]
use core2::io::{Read, Write};
#[cfg(not(feature = "no_std"))]
use std::io::{Read, Write};

#[test]
Expand Down
Loading

0 comments on commit b10f88a

Please sign in to comment.