Skip to content

Commit adcf6af

Browse files
committed
lib: enable no-std compatibility
Add a default `std` feature, and use compatible data structures from `alloc`, `core`, and `core2` for `no-std` builds. To build for `no-std` pass `--no-default-features` on the command line, or `default-features = false` in the Cargo.toml of another library/binary using `lzma-rs`.
1 parent da82bd1 commit adcf6af

18 files changed

+116
-27
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@ byteorder = "1.4.3"
1616
crc = "3.0.0"
1717
log = { version = "0.4.17", optional = true }
1818
env_logger = { version = "0.9.0", optional = true }
19+
core2 = "0.4"
1920

2021
[dev-dependencies]
2122
rust-lzma = "0.5"
2223

2324
[features]
25+
default = ["std"]
2426
enable_logging = ["env_logger", "log"]
2527
stream = []
2628
raw_decoder = []
29+
std = []
2730

2831
[package.metadata.docs.rs]
2932
features = ["stream", "raw_decoder"]

src/decode/lzbuffer.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
use crate::error;
2+
#[cfg(not(feature = "std"))]
3+
use core2::io;
4+
#[cfg(feature = "std")]
25
use std::io;
36

47
pub trait LzBuffer<W>

src/decode/lzma.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ use crate::decode::rangecoder::{BitTree, LenDecoder, RangeDecoder};
33
use crate::decompress::{Options, UnpackedSize};
44
use crate::error;
55
use crate::util::vec2d::Vec2D;
6+
#[cfg(not(feature = "std"))]
7+
use alloc::string::String;
68
use byteorder::{LittleEndian, ReadBytesExt};
9+
#[cfg(not(feature = "std"))]
10+
use core2::io;
11+
#[cfg(feature = "std")]
712
use std::io;
813

914
/// Maximum input data that can be processed in one iteration.
@@ -163,7 +168,7 @@ impl LzmaParams {
163168
pub(crate) struct DecoderState {
164169
// Buffer input data here if we need more for decompression. Up to
165170
// MAX_REQUIRED_INPUT bytes can be consumed during one iteration.
166-
partial_input_buf: std::io::Cursor<[u8; MAX_REQUIRED_INPUT]>,
171+
partial_input_buf: io::Cursor<[u8; MAX_REQUIRED_INPUT]>,
167172
pub(crate) lzma_props: LzmaProperties,
168173
unpacked_size: Option<u64>,
169174
literal_probs: Vec2D<u16>,
@@ -186,7 +191,7 @@ impl DecoderState {
186191
pub fn new(lzma_props: LzmaProperties, unpacked_size: Option<u64>) -> Self {
187192
lzma_props.validate();
188193
DecoderState {
189-
partial_input_buf: std::io::Cursor::new([0; MAX_REQUIRED_INPUT]),
194+
partial_input_buf: io::Cursor::new([0; MAX_REQUIRED_INPUT]),
190195
lzma_props,
191196
unpacked_size,
192197
literal_probs: Vec2D::init(0x400, (1 << (lzma_props.lc + lzma_props.lp), 0x300)),
@@ -404,7 +409,7 @@ impl DecoderState {
404409
range: u32,
405410
code: u32,
406411
) -> error::Result<()> {
407-
let mut temp = std::io::Cursor::new(buf);
412+
let mut temp = io::Cursor::new(buf);
408413
let mut rangecoder = RangeDecoder::from_parts(&mut temp, range, code);
409414
let _ = self.process_next_inner(output, &mut rangecoder, false)?;
410415
Ok(())

src/decode/lzma2.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ use crate::decode::lzma::{DecoderState, LzmaProperties};
33
use crate::decode::{lzbuffer, rangecoder};
44
use crate::error;
55
use byteorder::{BigEndian, ReadBytesExt};
6-
use std::io;
7-
use std::io::Read;
6+
#[cfg(not(feature = "std"))]
7+
use core2::io::{self, Read};
8+
#[cfg(feature = "std")]
9+
use std::io::{self, Read};
810

911
#[derive(Debug)]
1012
/// Raw decoder for LZMA2.

src/decode/rangecoder.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use crate::decode::util;
22
use crate::error;
33
use byteorder::{BigEndian, ReadBytesExt};
4+
#[cfg(not(feature = "std"))]
5+
use core2::io;
6+
#[cfg(feature = "std")]
47
use std::io;
58

69
pub struct RangeDecoder<'a, R>

src/decode/stream.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,18 @@ use crate::decode::lzma::{DecoderState, LzmaParams};
33
use crate::decode::rangecoder::RangeDecoder;
44
use crate::decompress::Options;
55
use crate::error::Error;
6-
use std::fmt::Debug;
6+
#[cfg(not(feature = "std"))]
7+
use core::fmt::{self, Debug};
8+
#[cfg(not(feature = "std"))]
9+
use core::u64::MAX as U64_MAX;
10+
#[cfg(not(feature = "std"))]
11+
use core2::io::{self, BufRead, Cursor, Read, Write};
12+
#[cfg(feature = "std")]
13+
use std::fmt::{self, Debug};
14+
#[cfg(feature = "std")]
715
use std::io::{self, BufRead, Cursor, Read, Write};
16+
#[cfg(feature = "std")]
17+
use std::u64::MAX as U64_MAX;
818

919
/// Minimum header length to be read.
1020
/// - props: u8 (1 byte)
@@ -51,7 +61,7 @@ impl<W> Debug for RunState<W>
5161
where
5262
W: Write,
5363
{
54-
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
64+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
5565
fmt.debug_struct("RunState")
5666
.field("range", &self.range)
5767
.field("code", &self.code)
@@ -212,7 +222,7 @@ impl<W> Debug for Stream<W>
212222
where
213223
W: Write + Debug,
214224
{
215-
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
225+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
216226
fmt.debug_struct("Stream")
217227
.field("tmp", &self.tmp.position())
218228
.field("state", &self.state)
@@ -278,7 +288,7 @@ where
278288
// reset the cursor because we may have partial reads
279289
input.set_position(0);
280290
let bytes_read = input.read(&mut self.tmp.get_mut()[..])?;
281-
let bytes_read = if bytes_read < std::u64::MAX as usize {
291+
let bytes_read = if bytes_read < U64_MAX as usize {
282292
bytes_read as u64
283293
} else {
284294
return Err(io::Error::new(
@@ -351,6 +361,8 @@ impl From<Error> for io::Error {
351361
#[cfg(test)]
352362
mod test {
353363
use super::*;
364+
#[cfg(not(feature = "std"))]
365+
use alloc::vec::Vec;
354366

355367
/// Test an empty stream
356368
#[test]

src/decode/util.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#[cfg(not(feature = "std"))]
2+
use core2::io;
3+
#[cfg(feature = "std")]
14
use std::io;
25

36
pub fn read_tag<R: io::BufRead>(input: &mut R, tag: &[u8]) -> io::Result<bool> {

src/decode/xz.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@ use crate::decode::util;
55
use crate::error;
66
use crate::xz::crc::{CRC32, CRC64};
77
use crate::xz::{footer, header, CheckMethod, StreamFlags};
8+
#[cfg(not(feature = "std"))]
9+
use alloc::vec::Vec;
810
use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
9-
use std::io;
10-
use std::io::Read;
11+
#[cfg(not(feature = "std"))]
12+
use core2::io::{self, Read};
13+
#[cfg(feature = "std")]
14+
use std::io::{self, Read};
1115

1216
#[derive(Debug)]
1317
struct Record {

src/encode/dumbencoder.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use crate::compress::{Options, UnpackedSize};
22
use crate::encode::rangecoder;
33
use byteorder::{LittleEndian, WriteBytesExt};
4+
#[cfg(not(feature = "std"))]
5+
use core2::io;
6+
#[cfg(feature = "std")]
47
use std::io;
58

69
pub struct Encoder<'a, W>

src/encode/lzma2.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
#[cfg(not(feature = "std"))]
2+
use alloc::vec;
13
use byteorder::{BigEndian, WriteBytesExt};
4+
#[cfg(not(feature = "std"))]
5+
use core2::io;
6+
#[cfg(feature = "std")]
27
use std::io;
38

49
pub fn encode_stream<R, W>(input: &mut R, output: &mut W) -> io::Result<()>

src/encode/rangecoder.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
#[cfg(all(test, not(feature = "std")))]
2+
use alloc::{vec, vec::Vec};
13
use byteorder::WriteBytesExt;
4+
#[cfg(not(feature = "std"))]
5+
use core2::io;
6+
#[cfg(feature = "std")]
27
use std::io;
38

49
pub struct RangeEncoder<'a, W>

src/encode/util.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#[cfg(not(feature = "std"))]
2+
use core2::io;
3+
#[cfg(feature = "std")]
14
use std::io;
25

36
// A Write computing a digest on the bytes written.

src/encode/xz.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ use crate::encode::{lzma2, util};
33
use crate::xz::crc::CRC32;
44
use crate::xz::{footer, header, CheckMethod, StreamFlags};
55
use byteorder::{LittleEndian, WriteBytesExt};
6-
use std::io;
7-
use std::io::Write;
6+
#[cfg(not(feature = "std"))]
7+
use core2::io::{self, Write};
8+
#[cfg(feature = "std")]
9+
use std::io::{self, Write};
810

911
pub fn encode_stream<R, W>(input: &mut R, output: &mut W) -> io::Result<()>
1012
where

src/error.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
//! Error handling.
22
3-
use std::fmt::Display;
4-
use std::{io, result};
3+
#[cfg(not(feature = "std"))]
4+
use alloc::string::String;
5+
#[cfg(not(feature = "std"))]
6+
use core::fmt::{self, Display};
7+
#[cfg(not(feature = "std"))]
8+
use core::result;
9+
#[cfg(not(feature = "std"))]
10+
use core2::{error, io};
11+
#[cfg(feature = "std")]
12+
use std::fmt::{self, Display};
13+
#[cfg(feature = "std")]
14+
use std::{error, io, result};
515

616
/// Library errors.
717
#[derive(Debug)]
@@ -26,7 +36,7 @@ impl From<io::Error> for Error {
2636
}
2737

2838
impl Display for Error {
29-
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
3040
match self {
3141
Error::IoError(e) => write!(fmt, "io error: {}", e),
3242
Error::HeaderTooShort(e) => write!(fmt, "header too short: {}", e),
@@ -36,8 +46,8 @@ impl Display for Error {
3646
}
3747
}
3848

39-
impl std::error::Error for Error {
40-
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
49+
impl error::Error for Error {
50+
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
4151
match self {
4252
Error::IoError(e) | Error::HeaderTooShort(e) => Some(e),
4353
Error::LzmaError(_) | Error::XzError(_) => None,
@@ -48,15 +58,15 @@ impl std::error::Error for Error {
4858
#[cfg(test)]
4959
mod test {
5060
use super::Error;
61+
#[cfg(not(feature = "std"))]
62+
use core2::io;
63+
#[cfg(feature = "std")]
64+
use std::io;
5165

5266
#[test]
5367
fn test_display() {
5468
assert_eq!(
55-
Error::IoError(std::io::Error::new(
56-
std::io::ErrorKind::Other,
57-
"this is an error"
58-
))
59-
.to_string(),
69+
Error::IoError(io::Error::new(io::ErrorKind::Other, "this is an error")).to_string(),
6070
"io error: this is an error"
6171
);
6272
assert_eq!(

src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
//! Pure-Rust codecs for LZMA, LZMA2, and XZ.
22
#![cfg_attr(docsrs, feature(doc_cfg, doc_cfg_hide))]
3+
#![cfg_attr(no_std, not(feature(std)))]
34
#![deny(missing_docs)]
45
#![deny(missing_debug_implementations)]
56
#![forbid(unsafe_code)]
67

8+
#[cfg(not(feature = "std"))]
9+
extern crate alloc;
10+
711
#[macro_use]
812
mod macros;
913

@@ -15,6 +19,9 @@ pub mod error;
1519
mod util;
1620
mod xz;
1721

22+
#[cfg(not(feature = "std"))]
23+
use core2::io;
24+
#[cfg(feature = "std")]
1825
use std::io;
1926

2027
/// Compression helpers.

src/util/vec2d.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
#[cfg(not(feature = "std"))]
2+
use alloc::boxed::Box;
3+
#[cfg(not(feature = "std"))]
4+
use core::ops::{Index, IndexMut};
5+
#[cfg(feature = "std")]
16
use std::ops::{Index, IndexMut};
27

38
/// A 2 dimensional matrix in row-major order backed by a contiguous slice.

src/xz/header.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ use crate::error;
55
use crate::xz::crc::CRC32;
66
use crate::xz::StreamFlags;
77
use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
8+
#[cfg(not(feature = "std"))]
9+
use core2::io;
10+
#[cfg(feature = "std")]
11+
use std::io;
812

913
/// File format magic header signature, see sect. 2.1.1.1.
1014
pub(crate) const XZ_MAGIC: &[u8] = &[0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00];
@@ -19,7 +23,7 @@ impl StreamHeader {
1923
/// Parse a Stream Header from a buffered reader.
2024
pub(crate) fn parse<BR>(input: &mut BR) -> error::Result<Self>
2125
where
22-
BR: std::io::BufRead,
26+
BR: io::BufRead,
2327
{
2428
if !util::read_tag(input, XZ_MAGIC)? {
2529
return Err(error::Error::XzError(format!(

src/xz/mod.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
//! [spec]: https://tukaani.org/xz/xz-file-format.txt
66
77
use crate::error;
8+
#[cfg(not(feature = "std"))]
9+
use core2::io;
10+
#[cfg(feature = "std")]
811
use std::io;
912

1013
pub(crate) mod crc;
@@ -85,12 +88,19 @@ impl From<CheckMethod> for u8 {
8588
mod test {
8689
use super::*;
8790
use byteorder::{BigEndian, ReadBytesExt};
88-
use std::io::{Seek, SeekFrom};
91+
#[cfg(not(feature = "std"))]
92+
use core::u8::MAX as U8_MAX;
93+
#[cfg(not(feature = "std"))]
94+
use core2::io::{self, Seek, SeekFrom};
95+
#[cfg(feature = "std")]
96+
use std::io::{self, Seek, SeekFrom};
97+
#[cfg(feature = "std")]
98+
use std::u8::MAX as U8_MAX;
8999

90100
#[test]
91101
fn test_checkmethod_roundtrip() {
92102
let mut count_valid = 0;
93-
for input in 0..std::u8::MAX {
103+
for input in 0..U8_MAX {
94104
if let Ok(check) = CheckMethod::try_from(input) {
95105
let output: u8 = check.into();
96106
assert_eq!(input, output);
@@ -106,7 +116,7 @@ mod test {
106116
check_method: CheckMethod::Crc32,
107117
};
108118

109-
let mut cursor = std::io::Cursor::new(vec![0u8; 2]);
119+
let mut cursor = io::Cursor::new(vec![0u8; 2]);
110120
let len = input.serialize(&mut cursor).unwrap();
111121
assert_eq!(len, 2);
112122

0 commit comments

Comments
 (0)