Skip to content

Add support for no_std #39

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,77 @@ jobs:
command: clippy
args: -- -D warnings

check-no-std:
name: Check (no_std)
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2

- name: Install nightly toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true

- name: Run cargo check without std feature
uses: actions-rs/cargo@v1
with:
command: check
toolchain: nightly
args: --no-default-features

test-no-std:
name: Test Suite (no_std)
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2

- name: Install nightly toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true

- name: Run cargo test without std feature
uses: actions-rs/cargo@v1
with:
command: test
toolchain: nightly
args: --no-default-features

lints-no-std:
name: Lints
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2

- name: Install nightly toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
components: rustfmt, clippy

- name: Run cargo fmt
uses: actions-rs/cargo@v1
with:
command: fmt
toolchain: nightly
args: --all -- --check

- name: Run cargo clippy
uses: actions-rs/cargo@v1
with:
command: clippy
toolchain: nightly
args: --no-default-features -- -D warnings

# fails CI because criterion needs two versions of autocfg
#cargo-deny:
# name: Cargo Deny
Expand Down
16 changes: 14 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,26 @@ exclude = ["decodecorpus_files/*", "dict_tests/*", "fuzz_decodecorpus/*"]
readme = "Readme.md"

[dependencies]
byteorder = "1.4"
byteorder = { version = "1.4", default-features = false }
twox-hash = { version = "1.6", default-features = false }
thiserror = "1"
thiserror = { package = "thiserror-core", version = "1.0.38", default-features = false }

[dev-dependencies]
criterion = "0.3"
rand = "0.8.5"

[features]
default = ["std"]
std = ["thiserror/std"]

[[bench]]
name = "reversedbitreader_bench"
harness = false

[[bin]]
name = "zstd"
required-features = ["std"]

[[bin]]
name = "zstd_stream"
required-features = ["std"]
4 changes: 2 additions & 2 deletions src/blocks/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ pub enum BlockType {
Reserved,
}

impl std::fmt::Display for BlockType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
impl core::fmt::Display for BlockType {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
match self {
BlockType::Compressed => write!(f, "Compressed"),
BlockType::Raw => write!(f, "Raw"),
Expand Down
4 changes: 2 additions & 2 deletions src/blocks/literals_section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ pub enum LiteralsSectionParseError {
NotEnoughBytes { have: usize, need: u8 },
}

impl std::fmt::Display for LiteralsSectionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
impl core::fmt::Display for LiteralsSectionType {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
match self {
LiteralsSectionType::Compressed => write!(f, "Compressed"),
LiteralsSectionType::Raw => write!(f, "Raw"),
Expand Down
4 changes: 2 additions & 2 deletions src/blocks/sequence_section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ pub struct Sequence {
pub of: u32,
}

impl std::fmt::Display for Sequence {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
impl core::fmt::Display for Sequence {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(f, "LL: {}, ML: {}, OF: {}", self.ll, self.ml, self.of)
}
}
Expand Down
42 changes: 16 additions & 26 deletions src/decoding/block_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::blocks::literals_section::LiteralsSectionParseError;
use crate::blocks::sequence_section::SequencesHeaderParseError;
use crate::decoding::scratch::DecoderScratch;
use crate::decoding::sequence_execution::execute_sequences;
use std::io::{self, Read};
use crate::io::{self, Read};

pub struct BlockDecoder {
header_buffer: [u8; 3],
Expand Down Expand Up @@ -203,12 +203,12 @@ impl BlockDecoder {
let mut section = LiteralsSection::new();
let bytes_in_literals_header = section.parse_from_header(raw)?;
let raw = &raw[bytes_in_literals_header as usize..];
if crate::VERBOSE {
println!(
"Found {} literalssection with regenerated size: {}, and compressed size: {:?}",
section.ls_type, section.regenerated_size, section.compressed_size
);
}
vprintln!(
"Found {} literalssection with regenerated size: {}, and compressed size: {:?}",
section.ls_type,
section.regenerated_size,
section.compressed_size
);

let upper_limit_for_literals = match section.compressed_size {
Some(x) => x as usize,
Expand All @@ -227,9 +227,7 @@ impl BlockDecoder {
}

let raw_literals = &raw[..upper_limit_for_literals];
if crate::VERBOSE {
println!("Slice for literals: {}", raw_literals.len());
}
vprintln!("Slice for literals: {}", raw_literals.len());

workspace.literals_buffer.clear(); //all literals of the previous block must have been used in the sequence execution anyways. just be defensive here
let bytes_used_in_literals_section = decode_literals(
Expand All @@ -247,20 +245,16 @@ impl BlockDecoder {
assert!(bytes_used_in_literals_section == upper_limit_for_literals as u32);

let raw = &raw[upper_limit_for_literals..];
if crate::VERBOSE {
println!("Slice for sequences with headers: {}", raw.len());
}
vprintln!("Slice for sequences with headers: {}", raw.len());

let mut seq_section = SequencesHeader::new();
let bytes_in_sequence_header = seq_section.parse_from_header(raw)?;
let raw = &raw[bytes_in_sequence_header as usize..];
if crate::VERBOSE {
println!(
"Found sequencessection with sequences: {} and size: {}",
seq_section.num_sequences,
raw.len()
);
}
vprintln!(
"Found sequencessection with sequences: {} and size: {}",
seq_section.num_sequences,
raw.len()
);

assert!(
u32::from(bytes_in_literals_header)
Expand All @@ -269,9 +263,7 @@ impl BlockDecoder {
+ raw.len() as u32
== header.content_size
);
if crate::VERBOSE {
println!("Slice for sequences: {}", raw.len());
}
vprintln!("Slice for sequences: {}", raw.len());

if seq_section.num_sequences != 0 {
decode_sequences(
Expand All @@ -280,9 +272,7 @@ impl BlockDecoder {
&mut workspace.fse,
&mut workspace.sequences,
)?;
if crate::VERBOSE {
println!("Executing sequences");
}
vprintln!("Executing sequences");
execute_sequences(workspace)?;
} else {
workspace.buffer.push(&workspace.literals_buffer);
Expand Down
41 changes: 23 additions & 18 deletions src/decoding/decodebuffer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::hash::Hasher;
use std::io;
use crate::io::{Error, Read, Write};
use alloc::vec::Vec;
use core::hash::Hasher;

use twox_hash::XxHash64;

Expand All @@ -23,8 +24,8 @@ pub enum DecodebufferError {
OffsetTooBig { offset: usize, buf_len: usize },
}

impl io::Read for Decodebuffer {
fn read(&mut self, target: &mut [u8]) -> io::Result<usize> {
impl Read for Decodebuffer {
fn read(&mut self, target: &mut [u8]) -> Result<usize, Error> {
let max_amount = self.can_drain_to_window_size().unwrap_or(0);
let amount = max_amount.min(target.len());

Expand Down Expand Up @@ -176,7 +177,7 @@ impl Decodebuffer {
}
}

pub fn drain_to_window_size_writer(&mut self, mut sink: impl io::Write) -> io::Result<usize> {
pub fn drain_to_window_size_writer(&mut self, mut sink: impl Write) -> Result<usize, Error> {
match self.can_drain_to_window_size() {
None => Ok(0),
Some(can_drain) => {
Expand All @@ -199,14 +200,14 @@ impl Decodebuffer {
vec
}

pub fn drain_to_writer(&mut self, mut sink: impl io::Write) -> io::Result<usize> {
pub fn drain_to_writer(&mut self, mut sink: impl Write) -> Result<usize, Error> {
let len = self.buffer.len();
self.drain_to(len, |buf| write_all_bytes(&mut sink, buf))?;

Ok(len)
}

pub fn read_all(&mut self, target: &mut [u8]) -> io::Result<usize> {
pub fn read_all(&mut self, target: &mut [u8]) -> Result<usize, Error> {
let amount = self.buffer.len().min(target.len());

let mut written = 0;
Expand All @@ -224,8 +225,8 @@ impl Decodebuffer {
fn drain_to(
&mut self,
amount: usize,
mut write_bytes: impl FnMut(&[u8]) -> (usize, io::Result<()>),
) -> io::Result<()> {
mut write_bytes: impl FnMut(&[u8]) -> (usize, Result<(), Error>),
) -> Result<(), Error> {
if amount == 0 {
return Ok(());
}
Expand Down Expand Up @@ -280,7 +281,7 @@ impl Decodebuffer {
}

/// Like Write::write_all but returns partial write length even on error
fn write_all_bytes(mut sink: impl io::Write, buf: &[u8]) -> (usize, io::Result<()>) {
fn write_all_bytes(mut sink: impl Write, buf: &[u8]) -> (usize, Result<(), Error>) {
let mut written = 0;
while written < buf.len() {
match sink.write(&buf[written..]) {
Expand All @@ -294,7 +295,11 @@ fn write_all_bytes(mut sink: impl io::Write, buf: &[u8]) -> (usize, io::Result<(
#[cfg(test)]
mod tests {
use super::Decodebuffer;
use std::io::Write;
use crate::io::{Error, ErrorKind, Write};

extern crate std;
use alloc::vec;
use alloc::vec::Vec;

#[test]
fn short_writer() {
Expand All @@ -304,7 +309,7 @@ mod tests {
}

impl Write for ShortWriter {
fn write(&mut self, buf: &[u8]) -> std::result::Result<usize, std::io::Error> {
fn write(&mut self, buf: &[u8]) -> std::result::Result<usize, Error> {
if buf.len() > self.write_len {
self.buf.extend_from_slice(&buf[..self.write_len]);
Ok(self.write_len)
Expand All @@ -314,7 +319,7 @@ mod tests {
}
}

fn flush(&mut self) -> std::result::Result<(), std::io::Error> {
fn flush(&mut self) -> std::result::Result<(), Error> {
Ok(())
}
}
Expand Down Expand Up @@ -352,18 +357,18 @@ mod tests {
}

impl Write for WouldblockWriter {
fn write(&mut self, buf: &[u8]) -> std::result::Result<usize, std::io::Error> {
fn write(&mut self, buf: &[u8]) -> std::result::Result<usize, Error> {
if self.last_blocked < self.block_every {
self.buf.extend_from_slice(buf);
self.last_blocked += 1;
Ok(buf.len())
} else {
self.last_blocked = 0;
Err(std::io::Error::from(std::io::ErrorKind::WouldBlock))
Err(Error::from(ErrorKind::WouldBlock))
}
}

fn flush(&mut self) -> std::result::Result<(), std::io::Error> {
fn flush(&mut self) -> std::result::Result<(), Error> {
Ok(())
}
}
Expand All @@ -390,7 +395,7 @@ mod tests {
}
}
Err(e) => {
if e.kind() == std::io::ErrorKind::WouldBlock {
if e.kind() == ErrorKind::WouldBlock {
continue;
} else {
panic!("Unexpected error {:?}", e);
Expand All @@ -410,7 +415,7 @@ mod tests {
}
}
Err(e) => {
if e.kind() == std::io::ErrorKind::WouldBlock {
if e.kind() == ErrorKind::WouldBlock {
continue;
} else {
panic!("Unexpected error {:?}", e);
Expand Down
3 changes: 2 additions & 1 deletion src/decoding/dictionary.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::convert::TryInto;
use alloc::vec::Vec;
use core::convert::TryInto;

use crate::decoding::scratch::FSEScratch;
use crate::decoding::scratch::HuffmanScratch;
Expand Down
5 changes: 2 additions & 3 deletions src/decoding/literals_section_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::super::blocks::literals_section::{LiteralsSection, LiteralsSectionTyp
use super::bit_reader_reverse::{BitReaderReversed, GetBitsError};
use super::scratch::HuffmanScratch;
use crate::huff0::{HuffmanDecoder, HuffmanDecoderError, HuffmanTableError};
use alloc::vec::Vec;

#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
Expand Down Expand Up @@ -75,9 +76,7 @@ fn decompress_literals(
LiteralsSectionType::Compressed => {
//read Huffman tree description
bytes_read += scratch.table.build_decoder(source)?;
if crate::VERBOSE {
println!("Built huffman table using {} bytes", bytes_read);
}
vprintln!("Built huffman table using {} bytes", bytes_read);
}
LiteralsSectionType::Treeless => {
if scratch.table.max_num_bits == 0 {
Expand Down
Loading