simple_encode 0.1.0

Dead simple b64/hex encoding/decoding.
Documentation
const ALPHABET: [char; 64] = [
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
    'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
];

fn get_hex_char(b: u8) -> char {
    match b {
        0 => '0',
        1 => '1',
        2 => '2',
        3 => '3',
        4 => '4',
        5 => '5',
        6 => '6',
        7 => '7',
        8 => '8',
        9 => '9',
        10 => 'A',
        11 => 'B',
        12 => 'C',
        13 => 'D',
        14 => 'E',
        15 => 'F',
        _ => panic!("Too large: {}\t- Must be <= 15.")
    }
}

fn get_num_from_hex(c: char) -> u8 {
    match c {
        '0' => 0,
        '1' => 1,
        '2' => 2,
        '3' => 3,
        '4' => 4,
        '5' => 5,
        '6' => 6,
        '7' => 7,
        '8' => 8,
        '9' => 9,
        'A' | 'a' => 10,
        'B' | 'b' => 11,
        'C' | 'c' => 12,
        'D' | 'd' => 13,
        'E' | 'e' => 14,
        'F' | 'f' => 15,
        _ => panic!("Letter must be [0-9A-Fa-f]: {}", c)
    }
}

pub fn base64_encode(bytes: Vec<u8>) -> String {
    let mut encoded = String::new();

    let mut iter = bytes.into_iter();
    loop {
        let a = iter.next();
        let b = iter.next();
        let c = iter.next();

        let p: usize;
        let mut q: usize;
        let mut r: usize;
        let s: usize;

        match a {
            Some(n) => {
                p = ((n & 0b11111100) >> 2) as usize;
                q = ((n & 0b00000011) << 4) as usize;

                encoded.push(ALPHABET[p]);
            }

            None => break
        }

        match b {
            Some(n) => {
                q |= ((n & 0b11110000) >> 4) as usize;
                r = ((n & 0b00001111) << 2) as usize;

                encoded.push(ALPHABET[q]);
            }

            None => {
                encoded.push(ALPHABET[q]);
                encoded.push_str("==");
                break;
            }
        }

        match c {
            Some(n) => {
                r |= ((n & 0b11000000) >> 6) as usize;
                s = (n & 0b00111111) as usize;

                encoded.push(ALPHABET[r]);
                encoded.push(ALPHABET[s]);
            }

            None => {
                encoded.push(ALPHABET[r]);
                encoded.push('=');
                break;
            }
        }
    }

    encoded
}

pub fn base64_decode(enc: String) -> Vec<u8> {
    assert!(enc.len() % 4 == 0, "Base 64 Encoding must be multiple of four.");
    let mut dec: Vec<u8> = Vec::new();

    let chars = enc.chars();
    let mut nums = chars.map(|x| ALPHABET.iter().position(|y| *y == x))
                        .collect::<Vec<Option<usize>>>().into_iter();

    loop {
        let p = nums.next().unwrap_or(None);
        let q = nums.next().unwrap_or(None);
        let r = nums.next().unwrap_or(None);
        let s = nums.next().unwrap_or(None);

        let mut a: u8;
        let mut b: u8;
        let mut c: u8;

        match p {
            Some(n) => {
                a = (n << 2) as u8;
            }

            None => break
        }

        match q {
            Some(n) => {
                a |= ((n & 0b00110000) >> 4) as u8;
                b = ((n & 0b00001111) << 4) as u8;

                dec.push(a);
            }

            None => break
        }

        match r {
            Some(n) => {
                b |= ((n & 0b00111100) >> 2) as u8;
                c = ((n & 0b00000011) << 6) as u8;

                dec.push(b);
            }

            None => break
        }

        match s {
            Some(n) => {
                c |= (n & 0b00111111) as u8;

                dec.push(c);
            }

            None => break
        }
    }

    dec
}

pub fn hex_encode(bytes: Vec<u8>) -> String {
    let mut enc = String::new();

    for b in bytes {
        enc.push(get_hex_char((b & 0xF0) >> 4));
        enc.push(get_hex_char(b & 0x0F));
    }

    enc
}

pub fn hex_decode(hex: String) -> Vec<u8> {
    assert!(hex.len() % 2 == 0, "Hex must be multiple of two.");

    let mut nums: Vec<u8> = Vec::new();
    let mut chars = hex.chars();

    loop {
        let a = chars.next();
        let b = chars.next();

        if a.is_none() {
            break;
        }

        nums.push((get_num_from_hex(a.unwrap()) << 4) | get_num_from_hex(b.unwrap()));
    }

    nums
}

#[test]
fn test_base64_encode() {
    let v: Vec<u8> = "this is a test sentence".to_string().into_bytes();
    assert!(base64_encode(v) == "dGhpcyBpcyBhIHRlc3Qgc2VudGVuY2U=");
}

#[test]
fn test_base64_decode() {
    let s: String = "dGhpcyBpcyBhIHRlc3Qgc2VudGVuY2U=".to_string();
    assert!(String::from_utf8(base64_decode(s)).expect("Couln't create string.") ==
            "this is a test sentence".to_string());
}

#[test]
fn test_hex_encode() {
    let v: Vec<u8> = vec![0x3a, 0xf1, 0x8c, 0xe0];
    assert!(hex_encode(v) == "3AF18CE0".to_string());
}

#[test]
fn test_hex_decode() {
    let s = "3A8CCEF001".to_string();
    let v: Vec<u8> = vec![0x3a, 0x8c, 0xce, 0xf0, 0x01];
    assert!(hex_decode(s) == v);
}

#[test]
fn matasano() {
    let vec = hex_decode("49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d".to_string());
    let b64 = base64_encode(vec);

    assert!(b64 == "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t".to_string())
}