bzip2/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
//! Bzip compression for Rust
//!
//! This library contains bindings to [`libbz2`] to support bzip compression and
//! decompression for Rust. The streams offered in this library are primarily
//! found in the [`mod@read`] and [`mod@write`] modules. Both compressors and
//! decompressors are available in each module depending on what operation you
//! need.
//!
//! A more low-level interface, much closer to the interface of [`libbz2`], is
//! available via the [`Compress`] and [`Decompress`] structs.
//!
//! [`libbz2`]: https://sourceware.org/bzip2/manual/manual.html
//!
//! # Example
//!
//! ```
//! use std::io::{BufRead, Read, Write};
//! use bzip2::Compression;
//! use bzip2::read::{BzEncoder, BzDecoder};
//!
//! // Round trip some bytes from a byte source, into a compressor, into a
//! // decompressor, and finally into a vector.
//! let data = "Hello, World!".as_bytes();
//! let compressor = BzEncoder::new(data, Compression::best());
//! let mut decompressor = BzDecoder::new(compressor);
//!
//! let mut contents = String::new();
//! decompressor.read_to_string(&mut contents).unwrap();
//! assert_eq!(contents, "Hello, World!");
//! ```
//!
//! # Multistreams (e.g. Wikipedia or pbzip2)
//!
//! Some tools such as pbzip2 or data from sources such as Wikipedia
//! are encoded as so called bzip2 "multistreams," meaning they
//! contain back to back chunks of bzip'd data. `BzDecoder` does not
//! attempt to convert anything after the the first bzip chunk in the
//! source stream. Thus, if you wish to decode all bzip chunks from
//! the input until end of file, use `MultiBzDecoder`.
//!
//! *Protip*: If you use `BzDecoder` to decode data and the output is
//! incomplete and exactly 900K bytes, you probably need a
//! `MultiBzDecoder`.
//!
//! All methods are internally capable of working with streams that may return
//! [`ErrorKind::WouldBlock`](std::io::ErrorKind::WouldBlock) when they're not
//! ready to perform the particular operation.
//!
//! Note that care needs to be taken when using these objects, however. The
//! Tokio runtime, in particular, requires that data is fully flushed before
//! dropping streams. For compatibility with blocking streams all streams are
//! flushed/written when they are dropped, and this is not always a suitable
//! time to perform I/O. If I/O streams are flushed before drop, however, then
//! these operations will be a noop.
#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/bzip2/")]
#[cfg(not(feature = "libbz2-rs-sys"))]
extern crate bzip2_sys as ffi;
#[cfg(feature = "libbz2-rs-sys")]
extern crate libbz2_rs_sys as ffi;
#[cfg(test)]
extern crate partial_io;
#[cfg(test)]
extern crate quickcheck;
#[cfg(test)]
extern crate rand;
pub use mem::{Action, Compress, Decompress, Error, Status};
mod mem;
pub mod bufread;
pub mod read;
pub mod write;
/// When compressing data, the compression level can be specified by a value in
/// this enum.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Compression(u32);
impl Compression {
/// Create a new compression spec with a specific numeric level in the range `1..=9`.
///
/// # Panics
///
/// A level outside of the `1..=9` range will throw a panic. Use [`Self::try_new`] to
/// gracefully handle invalid levels (e.g. from user input).
#[track_caller]
pub const fn new(level: u32) -> Compression {
match Self::try_new(level) {
Some(v) => v,
None => panic!("expected a compression level in the range 1..=9"),
}
}
/// Create a new compression spec with a specific numeric level in the range `1..=9`.
pub const fn try_new(level: u32) -> Option<Compression> {
match level {
1..=9 => Some(Compression(level)),
_ => None,
}
}
/// Do not compress.
#[deprecated(since = "0.5.1", note = "libbz2 does not support compression level 0")]
pub fn none() -> Compression {
Compression(0)
}
/// Optimize for the best speed of encoding.
pub const fn fast() -> Compression {
Compression(1)
}
/// Optimize for smallest output size.
pub const fn best() -> Compression {
Compression(9)
}
/// Return the compression level as an integer.
pub const fn level(&self) -> u32 {
self.0
}
}
impl Default for Compression {
/// Choose the default compression, a balance between speed and size.
fn default() -> Compression {
Compression(6)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
#[should_panic]
fn new_level_0() {
Compression::new(0);
}
#[test]
#[should_panic]
fn new_level_10() {
Compression::new(10);
}
#[test]
fn try_new() {
assert!(Compression::try_new(0).is_none());
assert!(Compression::try_new(10).is_none());
assert_eq!(Compression::try_new(1), Some(Compression::fast()));
assert_eq!(Compression::try_new(6), Some(Compression::default()));
assert_eq!(Compression::try_new(9), Some(Compression::best()));
}
}