pub struct HuffTree<L: HuffLetter> { /* private fields */ }Expand description
Struct representing a Huffman Tree with an alphabet of
type implementing HuffLetter
A HuffTree can be initialized in two ways:
- from a struct implementing the
Weights<L>trait (from_weights), whereLmust implement theHuffLettertrait - from a binary representation (
try_from_bin):BitVec<Msb0, u8>, where in order to even get it,Lmust implement theHuffLetterAsBytestrait
Codes stored by the tree can be retrieved using the codes method
§How it works
When initialized with the HuffTree::from_weights method it
follows the steps of the Huffman Coding algorithm (duh):
- Creates standalone branches for every letter found in the given weights and pushes them onto a branch heap
- Finds two branches with the lowest weights
- Makes them children to a branch with a
Noneletter and the children’s summed up weight - Removes the two found branches from the heap and adds the newly created branch into it
- Repeats steps 2 to 4 until there’s only one branch left
- Sets the only branch left as root
- Recurses into the tree to set every branch’s code
- Every branch gets its parent’s code with its own position in the parent branch (left - 0, right - 1)
Initializing from bits goes as follows:
- Go through the
HuffTreeencoded in binary (big endian) bit by bit - Every 1 means a joint branch
- Every 0 means a letter branch followed by
size_of::<L> * 8bits representing the stored letter
§Examples
Initialization from ByteWeights
use huff_coding::{
bitvec::prelude::*,
prelude::{HuffTree, ByteWeights},
};
use std::collections::HashMap;
let tree = HuffTree::from_weights(
ByteWeights::from_bytes(b"abbccc")
);
let codes = tree.read_codes();
assert_eq!(
codes.get(&b'c').unwrap(),
&bitvec![Msb0, u8; 0]
);
assert_eq!(
codes.get(&b'b').unwrap(),
&bitvec![Msb0, u8; 1, 1]
);
assert_eq!(
codes.get(&b'a').unwrap(),
&bitvec![Msb0, u8; 1, 0]
);Initialization from HashMap<L, usize>:
use huff_coding::{
bitvec::prelude::*,
prelude::{HuffTree, Weights},
};
use std::collections::HashMap;
let mut weights = HashMap::new();
weights.insert(String::from("pudzian"), 1);
weights.insert(String::from("krol"), 2);
weights.insert(String::from("szef"), 3);
let tree = HuffTree::from_weights(weights);
let codes = tree.read_codes();
assert_eq!(
codes.get("szef").unwrap(),
&bitvec![Msb0, u8; 0]
);
assert_eq!(
codes.get("krol").unwrap(),
&bitvec![Msb0, u8; 1, 1]
);
assert_eq!(
codes.get("pudzian").unwrap(),
&bitvec![Msb0, u8; 1, 0]
);Representing and reading the tree from bits:
use huff_coding::prelude::{HuffTree, ByteWeights};
let tree = HuffTree::from_weights(
ByteWeights::from_bytes(b"abbccc")
);
let tree_bin = tree.as_bin();
// the tree's root's left child is a letter branch, which are encoded by a 0
assert_eq!(*tree_bin.get(1).unwrap(), false);
let new_tree = HuffTree::try_from_bin(tree_bin).unwrap();
// the newly created tree is identical, except in weights
assert_eq!(
tree.read_codes(),
new_tree.read_codes()
);
assert_ne!(
tree
.root()
.leaf()
.weight(),
new_tree
.root()
.leaf()
.weight()
);
// every weight in a HuffTree read from binary is set to 0
assert_eq!(
new_tree
.root()
.leaf()
.weight(),
0
);§Panics
When trying to create a HuffTree<L> from a type implementing
Weights<L> with len == 0:
use huff_coding::prelude::{HuffTree, Weights};
use std::collections::HashMap;
let weights = HashMap::<char, usize>::new();
// panics here at 'provided empty weights'
let tree = HuffTree::from_weights(weights);§Errors
When trying to create a HuffTree<L> from binary where the original’s
letter type is different than the one specified to be read:
use huff_coding::prelude::{HuffTree, ByteWeights};
let tree = HuffTree::from_weights(
ByteWeights::from_bytes(b"abbccc")
);
let tree_bin = tree.as_bin();
let new_tree = HuffTree::<u128>::try_from_bin(tree_bin)
.expect("this will return a FromBinError");or when providing a too small/big BitVec to create a HuffTree
use huff_coding::{
bitvec::prelude::*,
prelude::{HuffTree, ByteWeights},
};
let tree = HuffTree::<u128>::try_from_bin(bitvec![Msb0, u8; 0, 1])
.expect("this will return a FromBinError (provided BitVec is to small)");Implementations§
Source§impl<L: HuffLetter> HuffTree<L>
impl<L: HuffLetter> HuffTree<L>
Sourcepub fn from_weights<W: Weights<L>>(weights: W) -> Self
pub fn from_weights<W: Weights<L>>(weights: W) -> Self
Initialize the HuffTree with a struct implementing the Weights<L> trait,
where L implements HuffLetter
In order to get the tree represented in binary(Bitvec<Msb0, u8>) you must ensure
that L also implements HuffLetterAsBytes
§Examples
Initialization from ByteWeights
use huff_coding::{
bitvec::prelude::*,
prelude::{HuffTree, ByteWeights},
};
use std::collections::HashMap;
let tree = HuffTree::from_weights(
ByteWeights::from_bytes(b"deefff")
);
let codes = tree.read_codes();
assert_eq!(
codes.get(&b'f').unwrap(),
&bitvec![Msb0, u8; 0]
);
assert_eq!(
codes.get(&b'e').unwrap(),
&bitvec![Msb0, u8; 1, 1]
);
assert_eq!(
codes.get(&b'd').unwrap(),
&bitvec![Msb0, u8; 1, 0]
);Initialization from HashMap<L, usize>:
use huff_coding::{
bitvec::prelude::*,
prelude::{HuffTree, Weights},
};
use std::collections::HashMap;
let mut weights = HashMap::new();
weights.insert('ą', 1);
weights.insert('þ', 2);
weights.insert('😎', 3);
let tree = HuffTree::from_weights(weights);
let codes = tree.read_codes();
assert_eq!(
codes.get(&'😎').unwrap(),
&bitvec![Msb0, u8; 0]
);
assert_eq!(
codes.get(&'þ').unwrap(),
&bitvec![Msb0, u8; 1, 1]
);
assert_eq!(
codes.get(&'ą').unwrap(),
&bitvec![Msb0, u8; 1, 0]
);§Panics
When trying to create a HuffTree<L> from a type implementing
Weights<L> with len == 0:
use huff_coding::prelude::{HuffTree, Weights};
use std::collections::HashMap;
let weights = HashMap::<char, usize>::new();
// panics here at 'provided empty weights'
let tree = HuffTree::from_weights(weights);Sourcepub fn root(&self) -> &HuffBranch<L>
pub fn root(&self) -> &HuffBranch<L>
Return a reference to the tree’s root branch
Sourcepub fn root_mut(&mut self) -> &mut HuffBranch<L>
pub fn root_mut(&mut self) -> &mut HuffBranch<L>
Return a mutable reference to the tree’s root branch
Sourcepub fn read_codes(&self) -> HashMap<L, BitVec<Msb0, u8>>
pub fn read_codes(&self) -> HashMap<L, BitVec<Msb0, u8>>
Go down the tree reading every letter’s code and returning
a HashMap<L, BitVec<Msb0, u8>>
§Example
use huff_coding::{
bitvec::prelude::*,
prelude::{HuffTree, ByteWeights},
};
use std::collections::HashMap;
let tree = HuffTree::from_weights(
ByteWeights::from_bytes(b"ghhiii")
);
let codes = tree.read_codes();
let mut cmp_codes = HashMap::new();
cmp_codes.insert(b'i', bitvec![Msb0, u8; 0]);
cmp_codes.insert(b'h', bitvec![Msb0, u8; 1, 1]);
cmp_codes.insert(b'g', bitvec![Msb0, u8; 1, 0]);
assert_eq!(codes, cmp_codes);Sourcepub fn read_codes_with_hasher<S: BuildHasher>(
&self,
hash_builder: S,
) -> HashMap<L, BitVec<Msb0, u8>, S>
pub fn read_codes_with_hasher<S: BuildHasher>( &self, hash_builder: S, ) -> HashMap<L, BitVec<Msb0, u8>, S>
Go down the tree reading every letter’s code and returning
a [HashMap<L, BitVec<Msb0, u8>, S>][HashMap] where S
is the provided hash builder (implementing BuildHasher)
§Example
use huff_coding::{
bitvec::prelude::*,
prelude::{HuffTree, ByteWeights},
};
use std::collections::{
HashMap,
hash_map::RandomState,
};
let tree = HuffTree::from_weights(
ByteWeights::from_bytes(b"ghhiii")
);
let codes = tree.read_codes_with_hasher(RandomState::default());
let mut cmp_codes = HashMap::new();
cmp_codes.insert(b'i', bitvec![Msb0, u8; 0]);
cmp_codes.insert(b'h', bitvec![Msb0, u8; 1, 1]);
cmp_codes.insert(b'g', bitvec![Msb0, u8; 1, 0]);
assert_eq!(codes, cmp_codes);Source§impl<L: HuffLetterAsBytes> HuffTree<L>
impl<L: HuffLetterAsBytes> HuffTree<L>
Sourcepub fn try_from_bin(bin: BitVec<Msb0, u8>) -> Result<Self, FromBinError<L>>
pub fn try_from_bin(bin: BitVec<Msb0, u8>) -> Result<Self, FromBinError<L>>
Try to read the provided BitVec<Msb0, u8> and
construct a HuffTree<L> from it.
Every weight in the newly created tree is set to 0
as they’re not stored in the binary representation
In order to call this method, L must implement HuffLetterAsBytes
§Decoding scheme
- Go bit by bit
- Create a
HuffBranchwith no letter (a joint branch) when a 1 is found - When a 0 is found, read next
size_of::<L>() * 8bits and create a value of typeLfrom them, inserting it then into aHuffBranch
§Example
use huff_coding::prelude::{HuffTree, ByteWeights};
let tree = HuffTree::from_weights(
ByteWeights::from_bytes(b"mnnooo")
);
let tree_bin = tree.as_bin();
let new_tree = HuffTree::try_from_bin(tree_bin).unwrap();
// the newly created tree is identical, except in weights
assert_eq!(
tree.read_codes(),
new_tree.read_codes()
);
assert_ne!(
tree
.root()
.leaf()
.weight(),
new_tree
.root()
.leaf()
.weight()
);
// every weight in a HuffTree read from binary is set to 0
assert_eq!(
new_tree
.root()
.leaf()
.weight(),
0
);§Errors
When trying to create a HuffTree<L>from binary where the original’s
letter type is different than the one specified to be read:
use huff_coding::prelude::{HuffTree, ByteWeights};
let tree = HuffTree::from_weights(
ByteWeights::from_bytes(b"abbccc")
);
let tree_bin = tree.as_bin();
let new_tree = HuffTree::<u128>::try_from_bin(tree_bin)
.expect("this will return a FromBinError");or when providing a too small/big BitVec to create a HuffTree
use huff_coding::{
bitvec::prelude::*,
prelude::{HuffTree, ByteWeights},
};
let tree = HuffTree::<u128>::try_from_bin(bitvec![Msb0, u8; 0, 1])
.expect("this will return a FromBinError (provided BitVec is to small)");Sourcepub fn as_bin(&self) -> BitVec<Msb0, u8>
pub fn as_bin(&self) -> BitVec<Msb0, u8>
Return a binary representation of the HuffTree<L>
(BitVec<Msb0, u8>)
In order to call this method, L must implement HuffLetterAsBytes
§Encoding scheme
- Recurse down the tree
- Every joint branch is encoded as a 1
- Every letter branch is encoded as a 0 and is followed by the letter itself encoded in binary
§Example
use huff_coding::prelude::{HuffTree, ByteWeights};
let tree = HuffTree::from_weights(
ByteWeights::from_bytes(b"abbccc")
);
let tree_bin = tree.as_bin();
assert_eq!(tree_bin.to_string(), "[10011000, 11100110, 00010011, 00010]");Trait Implementations§
Auto Trait Implementations§
impl<L> Freeze for HuffTree<L>where
L: Freeze,
impl<L> RefUnwindSafe for HuffTree<L>where
L: RefUnwindSafe,
impl<L> Send for HuffTree<L>where
L: Send,
impl<L> Sync for HuffTree<L>where
L: Sync,
impl<L> Unpin for HuffTree<L>where
L: Unpin,
impl<L> UnwindSafe for HuffTree<L>where
L: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> PipeAsRef for T
impl<T> PipeAsRef for T
Source§impl<T> PipeBorrow for T
impl<T> PipeBorrow for T
Source§impl<T> PipeDeref for T
impl<T> PipeDeref for T
Source§impl<T> PipeRef for T
impl<T> PipeRef for T
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&Self) -> R,
fn tap<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&Self) -> R,
Source§fn tap_dbg<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&Self) -> R,
fn tap_dbg<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&Self) -> R,
tap in debug builds, and does nothing in release builds.Source§fn tap_mut<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&mut Self) -> R,
fn tap_mut<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&mut Self) -> R,
Source§fn tap_mut_dbg<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&mut Self) -> R,
fn tap_mut_dbg<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&mut Self) -> R,
tap_mut in debug builds, and does nothing in release builds.Source§impl<T, U> TapAsRef<U> for Twhere
U: ?Sized,
impl<T, U> TapAsRef<U> for Twhere
U: ?Sized,
Source§fn tap_ref<F, R>(self, func: F) -> Self
fn tap_ref<F, R>(self, func: F) -> Self
Source§fn tap_ref_dbg<F, R>(self, func: F) -> Self
fn tap_ref_dbg<F, R>(self, func: F) -> Self
tap_ref in debug builds, and does nothing in release builds.Source§fn tap_ref_mut<F, R>(self, func: F) -> Self
fn tap_ref_mut<F, R>(self, func: F) -> Self
Source§impl<T, U> TapBorrow<U> for Twhere
U: ?Sized,
impl<T, U> TapBorrow<U> for Twhere
U: ?Sized,
Source§fn tap_borrow<F, R>(self, func: F) -> Self
fn tap_borrow<F, R>(self, func: F) -> Self
Source§fn tap_borrow_dbg<F, R>(self, func: F) -> Self
fn tap_borrow_dbg<F, R>(self, func: F) -> Self
tap_borrow in debug builds, and does nothing in release builds.Source§fn tap_borrow_mut<F, R>(self, func: F) -> Self
fn tap_borrow_mut<F, R>(self, func: F) -> Self
Source§impl<T> TapDeref for T
impl<T> TapDeref for T
Source§fn tap_deref_dbg<F, R>(self, func: F) -> Self
fn tap_deref_dbg<F, R>(self, func: F) -> Self
tap_deref in debug builds, and does nothing in release builds.Source§fn tap_deref_mut<F, R>(self, func: F) -> Self
fn tap_deref_mut<F, R>(self, func: F) -> Self
self for modification.