base16-rs 0.1.1

The base16-rs library in Rust offers capabilities for encoding and decoding data in Base16 format. By utilizing the hex library, you can transform data into its hexadecimal representation and also decode hexadecimal strings to retrieve the original data. This encoding technique is frequently employed for tasks involving data transmission and storage, as well as in situations where binary data necessitates representation in readable ASCII strings.
Documentation
use std::{env::VarError, ops::Index};

const BASE16_UPPER_TABLE: [u8; 16] = *b"0123456789ABCDEF";
const BASE16_LOWER_TABLE: [u8; 16] = *b"0123456789abcdef";

pub struct Decoder {}

impl Decoder {
    pub fn new() -> Self {
        Decoder {}
    }
}

impl Decoder {
    #[inline]
    pub fn decode_std(&self, src: &str) -> Result<Vec<u8>, usize> {
        let mut dst = Vec::with_capacity(src.len() / 2);

        let origin = src.to_lowercase();
        for ch in origin.chars() {
            let byte = ch as u8;
            let r = BASE16_LOWER_TABLE.binary_search(&byte)?;
            dst.push(r as u8)
        }

        let dst = dst
            .chunks_exact(2)
            .map(|bytes| {
                let b1 = bytes[0];
                let b2 = bytes[1];
                b1 << 4 | b2
            })
            .collect::<Vec<u8>>();

        Ok(dst)
    }
}

pub struct Encoder {
    typ: Type,
}

impl Encoder {
    pub fn new(typ: Type) -> Self {
        Encoder { typ }
    }
}

impl Encoder {
    pub fn encode_upper_to_string(&self, src: &[u8]) -> String {
        match self.typ {
            Type::StdEncoding => self
                .encode_upper_std(src)
                .into_iter()
                .map(|b| b as char)
                .collect(),
        }
    }

    pub fn encode_lower_to_string(&self, src: &[u8]) -> String {
        match self.typ {
            Type::StdEncoding => self
                .encode_lower_std(src)
                .into_iter()
                .map(|b| b as char)
                .collect(),
        }
    }

    #[inline]
    fn encode_upper_std(&self, src: &[u8]) -> Vec<u8> {
        self.encode_std(src, EncodeConfig::UPPER)
    }

    #[inline]
    fn encode_lower_std(&self, src: &[u8]) -> Vec<u8> {
        self.encode_std(src, EncodeConfig::LOWER)
    }

    #[inline]
    fn encode_std(&self, src: &[u8], cfg: EncodeConfig) -> Vec<u8> {
        let table = if cfg == EncodeConfig::LOWER {
            BASE16_LOWER_TABLE
        } else {
            BASE16_UPPER_TABLE
        };

        let mut dst = Vec::with_capacity(src.len() * 2);
        for b in src.iter() {
            let byte = *b;
            dst.push(table[(byte >> 4) as usize]);
            dst.push(table[(byte & 0x0F) as usize]);
        }
        dst
    }
}

pub enum Type {
    StdEncoding,
}

#[derive(PartialEq)]
enum EncodeConfig {
    UPPER,
    LOWER,
}

#[cfg(test)]
mod encode_tests {
    use super::*;
    use crate::base16::Type::StdEncoding;

    #[test]
    fn empty() {
        let buf: Vec<u8> = Vec::from("");
        let encoder = Encoder::new(StdEncoding);
        let result = encoder.encode_upper_to_string(&buf);
        assert_eq!(result, "");
    }

    #[test]
    fn number() {
        let buf: Vec<u8> = Vec::from("0123456789");
        let encoder = Encoder::new(StdEncoding);
        let result = encoder.encode_upper_to_string(&buf);
        assert_eq!(result, "30313233343536373839");
    }

    #[test]
    fn alpha() {
        let buf: Vec<u8> = Vec::from("abcdefghijklnmopqrstuvwxyz");
        let encoder = Encoder::new(StdEncoding);
        let result = encoder.encode_upper_to_string(&buf);
        assert_eq!(
            result,
            "6162636465666768696A6B6C6E6D6F707172737475767778797A"
        );
    }

    #[test]
    fn enter() {
        let buf: Vec<u8> = Vec::from(
            r#"abcdefghijklnmo
pqrstuvwxyz"#,
        );
        let encoder = Encoder::new(StdEncoding);
        let result = encoder.encode_upper_to_string(&buf);
        assert_eq!(
            result,
            "6162636465666768696A6B6C6E6D6F0A707172737475767778797A"
        );
    }
}
#[cfg(test)]
mod decode_tests {
    use super::*;
    use crate::base16::Type::StdEncoding;

    #[test]
    fn empty() {
        let buf: String = String::from("");
        let decoder = Decoder::new();
        let result = decoder.decode_std(&buf);
        assert_eq!(result, Ok(Vec::from("")));
    }

    #[test]
    fn number() {
        let buf: String = String::from("30313233343536373839");
        let decoder = Decoder::new();
        let result = decoder.decode_std(&buf);
        assert_eq!(result, Ok(Vec::from("0123456789")));
    }

    #[test]
    fn alpha() {
        let buf: String = String::from("6162636465666768696A6B6C6E6D6F707172737475767778797A");
        let decoder = Decoder::new();
        let result = decoder.decode_std(&buf);
        assert_eq!(result, Ok(Vec::from("abcdefghijklnmopqrstuvwxyz")));
    }
    #[test]
    fn error() {
        let buf: String = String::from("AFGHHFJ");
        let decoder = Decoder::new();
        let result = decoder.decode_std(&buf);
        assert_eq!(result, Err(16));
    }

    #[test]
    fn enter() {
        let buf: String = String::from("6162636465666768696A6B6C6E6D6F0A707172737475767778797A");
        let decoder = Decoder::new();
        let result = decoder.decode_std(&buf);
        assert_eq!(
            result,
            Ok(Vec::from(
                r#"abcdefghijklnmo
pqrstuvwxyz"#
            ))
        );
    }
}