Compare commits
3 commits
3a07eae54f
...
6fa7b62d26
| Author | SHA1 | Date | |
|---|---|---|---|
| 6fa7b62d26 | |||
| bf9212b79a | |||
| 7f0c1ada52 |
5 changed files with 55 additions and 11 deletions
|
|
@ -8,4 +8,4 @@ bitvec = "1.0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
quickcheck = "1"
|
quickcheck = "1"
|
||||||
quickcheck_macros = "1"
|
quickcheck_macros = "1"
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,12 @@ pub enum Node {
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
fn build(counts: &HashMap<u8, u32>) -> Option<Self> {
|
fn build(counts: &HashMap<u8, u32>) -> Option<Self> {
|
||||||
WeightedNode::build(counts).map(WeightedNode::unburden)
|
let branch = match WeightedNode::build(counts).map(WeightedNode::unburden)? {
|
||||||
|
leaf @ Node::Leaf { .. } => Self::join(leaf.clone(), leaf),
|
||||||
|
branch @ Node::Branch { .. } => branch,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(branch)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write to `buf` the sequence of bits that this tree has assigned `byte`.
|
/// Write to `buf` the sequence of bits that this tree has assigned `byte`.
|
||||||
|
|
@ -120,6 +125,13 @@ impl Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn join(path0: Self, path1: Self) -> Self {
|
||||||
|
Self::Branch {
|
||||||
|
path0: Box::new(path0),
|
||||||
|
path1: Box::new(path1),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Node {
|
impl fmt::Debug for Node {
|
||||||
|
|
|
||||||
28
src/id.rs
Normal file
28
src/id.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
use bitvec::prelude::{BitSlice, BitVec};
|
||||||
|
|
||||||
|
use crate::CompressionScheme;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Id;
|
||||||
|
|
||||||
|
impl CompressionScheme for Id {
|
||||||
|
type Header = ();
|
||||||
|
|
||||||
|
fn encode(src: &[u8], buf: &mut BitVec) -> Self::Header {
|
||||||
|
buf.extend_from_bitslice(BitSlice::<u8>::from_slice(src));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode(src: &BitSlice, (): &Self::Header, buf: &mut Vec<u8>) {
|
||||||
|
// TODO: is this actually fine
|
||||||
|
#[allow(clippy::unbuffered_bytes)]
|
||||||
|
for byte in src.bytes() {
|
||||||
|
buf.push(byte.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn header_size((): &Self::Header) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ use std::{
|
||||||
mod compression_scheme;
|
mod compression_scheme;
|
||||||
mod freq;
|
mod freq;
|
||||||
mod huffman;
|
mod huffman;
|
||||||
|
mod id;
|
||||||
mod rle;
|
mod rle;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
|
@ -15,18 +16,18 @@ use bitvec::vec::BitVec;
|
||||||
pub use compression_scheme::CompressionScheme;
|
pub use compression_scheme::CompressionScheme;
|
||||||
pub use freq::Freq;
|
pub use freq::Freq;
|
||||||
pub use huffman::Huffman;
|
pub use huffman::Huffman;
|
||||||
|
pub use id::Id;
|
||||||
pub use rle::Rle;
|
pub use rle::Rle;
|
||||||
|
|
||||||
fn main() -> Result<(), io::Error> {
|
fn main() -> Result<(), io::Error> {
|
||||||
let debug = env::args().any(|arg| arg == "--debug" || arg == "-d");
|
let debug = env::args().any(|arg| arg == "--debug" || arg == "-d");
|
||||||
|
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
let len_src = io::stdin().read_to_end(&mut buf)?;
|
io::stdin().read_to_end(&mut buf)?;
|
||||||
|
|
||||||
println!("Original: {len_src}");
|
|
||||||
|
|
||||||
let mut bitbuf = BitVec::new();
|
let mut bitbuf = BitVec::new();
|
||||||
|
|
||||||
|
run::<Id, _>(&buf, &mut bitbuf, "Original", debug);
|
||||||
run::<Rle, _>(&buf, &mut bitbuf, "rle", debug);
|
run::<Rle, _>(&buf, &mut bitbuf, "rle", debug);
|
||||||
run::<Freq, _>(&buf, &mut bitbuf, "freq", debug);
|
run::<Freq, _>(&buf, &mut bitbuf, "freq", debug);
|
||||||
run::<Huffman, _>(&buf, &mut bitbuf, "Huffman", debug);
|
run::<Huffman, _>(&buf, &mut bitbuf, "Huffman", debug);
|
||||||
|
|
@ -42,7 +43,7 @@ where
|
||||||
bitbuf.clear();
|
bitbuf.clear();
|
||||||
let header = Scheme::encode(buf, bitbuf);
|
let header = Scheme::encode(buf, bitbuf);
|
||||||
let len_freq = Scheme::header_size(&header) + bitbuf.len().div_ceil(8);
|
let len_freq = Scheme::header_size(&header) + bitbuf.len().div_ceil(8);
|
||||||
println!("{name}'d: {len_freq}");
|
println!("{name:>10}: {len_freq:>10}");
|
||||||
if debug {
|
if debug {
|
||||||
eprintln!("{name} header: {header:#?}\n");
|
eprintln!("{name} header: {header:#?}\n");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
13
src/test.rs
13
src/test.rs
|
|
@ -1,21 +1,24 @@
|
||||||
|
#![allow(clippy::needless_pass_by_value)]
|
||||||
|
|
||||||
|
use crate::{CompressionScheme, Freq, Huffman, Id, Rle};
|
||||||
use quickcheck_macros::quickcheck;
|
use quickcheck_macros::quickcheck;
|
||||||
|
|
||||||
use crate::{CompressionScheme, Freq, Huffman, Rle};
|
|
||||||
|
|
||||||
#[allow(clippy::needless_pass_by_value)]
|
|
||||||
#[quickcheck]
|
#[quickcheck]
|
||||||
fn roundtrip_freq(src: Vec<u8>) -> bool {
|
fn roundtrip_freq(src: Vec<u8>) -> bool {
|
||||||
Freq::idempotent_on(&src)
|
Freq::idempotent_on(&src)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_pass_by_value)]
|
|
||||||
#[quickcheck]
|
#[quickcheck]
|
||||||
fn roundtrip_rle(src: Vec<u8>) -> bool {
|
fn roundtrip_rle(src: Vec<u8>) -> bool {
|
||||||
Rle::idempotent_on(&src)
|
Rle::idempotent_on(&src)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_pass_by_value)]
|
|
||||||
#[quickcheck]
|
#[quickcheck]
|
||||||
fn roundtrip_huffman(src: Vec<u8>) -> bool {
|
fn roundtrip_huffman(src: Vec<u8>) -> bool {
|
||||||
Huffman::idempotent_on(&src)
|
Huffman::idempotent_on(&src)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[quickcheck]
|
||||||
|
fn roundtrip_id(src: Vec<u8>) -> bool {
|
||||||
|
Id::idempotent_on(&src)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue