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
//! This crate implements transformation algorithms to be used during compression.
//!
//! # Introduction
//! The transformation algorithms implemented in this crate are all reversible.
//! The original order of the data can be reproduced by using the `reverse` operation
//! defined by the `Transform` Trait.
use std::fmt;
use std::{error::Error, fmt::Display};
mod bwt;
mod movetofront;
mod runlength;

pub use bwt::BurrowWheeler;
pub use movetofront::MoveToFront;
pub use runlength::RunLength;

/// Trait for calculating transformations on byte level
pub trait Transform {
    fn transform(&mut self, source: &[u8]) -> Result<Vec<u8>, TransformError>;
    fn reverse(&mut self, source: &[u8]) -> Result<Vec<u8>, TransformError>;
}

/// An enum representing possible errors during transformation
#[derive(Debug)]
pub enum TransformError {
    /// Buffer is empty
    EmptyBufferError,
    /// Symbol is not found
    SymbolNotFound(u8),
    /// Missing index of Burrow Wheeler
    MissingIndex,
    /// Missing symbol in the reverse mapping of Burrow Wheeler
    MissingMapping(u8),
    /// Missing count of symbol
    MissingCountMap(u8, usize),
}

impl Error for TransformError {
    fn description(&self) -> &str {
        match *self {
            TransformError::EmptyBufferError => "Empty Buffer",
            TransformError::SymbolNotFound(_val) => "No Symbol",
            TransformError::MissingIndex => "Missing index position",
            TransformError::MissingMapping(_val) => "No Mapping",
            TransformError::MissingCountMap(_, _) => "Can not find enough occurences of symbol",
        }
    }
}

impl Display for TransformError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            TransformError::EmptyBufferError => write!(f, "Can not read because buffer is empty"),
            TransformError::SymbolNotFound(val) => write!(f, "Symbol [{:?}] not found", val),
            TransformError::MissingIndex => write!(f, "There is no index given"),
            TransformError::MissingMapping(val) => write!(f, "Mapping for [{:?}] is missing", val),
            TransformError::MissingCountMap(sym, c) => {
                write!(f, "Missing {:?}. occurence of symbol '{:?}'", c + 1, sym)
            }
        }
    }
}

#[cfg(test)]
#[allow(dead_code)]
pub mod tests {
    //! # Tests
    //! This module defines helper functions for testing transformation algorithms.
    use crate::Transform;
    use rand::{rngs::OsRng, RngCore};

    /// Helper function for testing one-way transformation
    pub fn transform<M: Transform + Default>(input: &[u8], expected: &[u8]) {
        let mut model: M = Default::default();
        let result = model.transform(&input).unwrap();
        assert_eq!(result, expected)
    }

    /// Helper function for testing reverse transformation
    pub fn reverse<M: Transform + Default>(input: &[u8], expected: &[u8]) {
        let mut model: M = Default::default();
        let result = model.reverse(&input).unwrap();
        assert_eq!(result, expected)
    }

    /// Helper function for testing transformation roundtrips
    pub fn roundtrip<M: Transform + Default>(input: &[u8]) {
        println!("Input:       {:?}", input);
        let mut model: M = Default::default();
        let tmp = model.transform(&input).unwrap();
        println!("Transformed: {:?}", tmp);
        let result = model.reverse(&tmp).unwrap();
        println!("Reversed:    {:?}", result);
        assert_eq!(result, input)
    }

    /// Helper function for testing random transformation roundtrips
    pub fn random_roundtrip<M: Transform + Default>(trips: usize, size: usize) {
        for _ in 0..trips {
            let mut input = vec![0u8; size];
            OsRng.fill_bytes(&mut input);
            let mut model: M = Default::default();
            let tmp = model.transform(&input).unwrap();
            let result = model.reverse(&tmp).unwrap();
            if result != input {
                println!("Input:       {:?}", input);
                println!("Transformed: {:?}", tmp);
                println!("Reversed:    {:?}", result);
            }
            assert_eq!(result, input)
        }
    }
}