gua64 0.0.6

六十四卦編碼,rust實現 如:“hello,世界”會編碼為“䷯䷬䷿䷶䷸䷬䷀䷌䷌䷎䷼䷲䷰䷳䷸䷘䷔䷭䷒〇”
Documentation
use std::collections::HashMap;
const GUA: &str = "䷁䷖䷇䷓䷏䷢䷬䷋\
䷎䷳䷦䷴䷽䷷䷞䷠\
䷆䷃䷜䷺䷧䷿䷮䷅\
䷭䷑䷯䷸䷟䷱䷛䷫\
䷗䷚䷂䷩䷲䷔䷐䷘\
䷣䷕䷾䷤䷶䷝䷰䷌\
䷒䷨䷻䷼䷵䷥䷹䷉\
䷊䷙䷄䷈䷡䷍䷪䷀";

const PADDING: char = '';

pub struct Gua64 {
    list: Vec<char>,
    dict: HashMap<char, u8>,
}

impl Gua64 {
    pub fn new() -> Self {
        let list: Vec<char> = GUA.chars().collect();
        let mut dict = HashMap::new();
        for (i, c) in list.iter().enumerate() {
            dict.insert(*c, i as u8);
        }
        Gua64 { list, dict }
    }

    pub fn encode(&self, input: &[u8]) -> String {
        let mut encoded = String::new();
        let mut index: u8;

        for chunk in input.chunks(3) {
            let chunk_len = chunk.len();

            index = chunk[0] >> 2;
            encoded.push(self.list[index as usize]);

            if chunk_len == 1 {
                index = (chunk[0] & 0x3) << 4;
                encoded.push(self.list[index as usize]);
                encoded.push(PADDING);
                encoded.push(PADDING);
                continue;
            }

            index = ((chunk[0] & 0x3) << 4) | (chunk[1] >> 4);
            encoded.push(self.list[index as usize]);

            if chunk_len == 2 {
                index = (chunk[1] & 0xF) << 2;
                encoded.push(self.list[index as usize]);
                encoded.push(PADDING);
                continue;
            }

            index = ((chunk[1] & 0xF) << 2) | (chunk[2] >> 6);
            encoded.push(self.list[index as usize]);

            index = chunk[2] & 0x3F;
            encoded.push(self.list[index as usize]);
        }

        encoded
    }

    pub fn decode(&self, input: &str) -> Vec<u8> {
        let mut values = Vec::new();

        for c in input.chars() {
            if let Some(&v) = self.dict.get(&c) {
                values.push(v);
            } else if c == PADDING {
                values.push(u8::MAX);
            } else {
                panic!("Invalid Gua64 character: {}", c);
            }
        }

        let mut decoded = Vec::new();
        for chunk in values.chunks(4) {
            if chunk.len() < 4 {
                panic!("Invalid Gua64 encoding");
            }

            decoded.push((chunk[0] << 2) | (chunk[1] >> 4));

            if chunk[2] != u8::MAX {
                decoded.push((chunk[1] << 4) | (chunk[2] >> 2));
            }

            if chunk[3] != u8::MAX {
                decoded.push((chunk[2] << 6) | chunk[3]);
            }
        }

        decoded
    }

    pub fn verify(&self, input: &str) -> bool {
        input
            .chars()
            .all(|c| self.dict.contains_key(&c) || c == PADDING)
    }
}