binhex-rs 0.1.0

Crate to read BinHex 4 encoded files
Documentation
#[derive(Clone, Default)]
enum State {
    #[default]
    Empty,
    Top6,
    Bottom2Top4,
    Top2Bottom4,
}

impl State {
    #[inline]
    fn advance(&self) -> Self {
        match self {
            Self::Empty => Self::Top6,
            Self::Top6 => Self::Bottom2Top4,
            Self::Bottom2Top4 => Self::Top2Bottom4,
            Self::Top2Bottom4 => Self::Empty,
        }
    }
}

#[derive(Clone, Default)]
/// In order to avoid using characters that are deemed unsafe for transmission
/// data is encoded from a stream of bytes into 6bit chunks, the decoder reverses
/// this operation
pub(crate) struct SixBitDecoder {
    state: State,
    partial: u8,
}

impl SixBitDecoder {
    pub(crate) fn new() -> Self {
        Self {
            state: Default::default(),
            partial: 0,
        }
    }

    pub(crate) fn next(&mut self, byte: u8) -> Option<u8> {
        let byte = byte & 0x3F;
        let out: u8;

        self.state = self.state.advance();

        match self.state {
            State::Top6 => {
                self.partial = byte << 2;
                return None;
            }
            State::Bottom2Top4 => {
                out = self.partial | (byte >> 4);
                self.partial = (byte & 0x0F) << 4;
            }
            State::Top2Bottom4 => {
                out = self.partial | (byte >> 2);
                self.partial = (byte & 0x03) << 6;
            }
            State::Empty => {
                out = self.partial | byte;
            }
        }

        Some(out)
    }
}

#[cfg(test)]
mod test {
    use super::SixBitDecoder;

    #[test]
    fn decoder() {
        let mut decoder = SixBitDecoder::new();
        assert_eq!(decoder.next(0xFF), None);
        assert_eq!(decoder.next(0xFF), Some(0xFFu8));
        assert_eq!(decoder.next(0xFF), Some(0xFFu8));
        assert_eq!(decoder.next(0xFF), Some(0xFFu8));
        assert_eq!(decoder.next(0xFF), None);

        let mut decoder = SixBitDecoder::new();
        assert_eq!(decoder.next(0b11_000000), None);
        assert_eq!(decoder.next(0b11_000000), Some(0));

        let mut decoder = SixBitDecoder::new();
        assert_eq!(decoder.next(0b11_101010), None);
        assert_eq!(decoder.next(0b11_100101), Some(0b10101010));
        assert_eq!(decoder.next(0b11_010100), Some(0b01010101));
        assert_eq!(decoder.next(0b11_000001), Some(0b00000001));
        assert_eq!(decoder.next(0b11_101010), None);

        let mut decoder = SixBitDecoder::new();
        assert_eq!(decoder.next(0x03), None);
        assert_eq!(decoder.next(0x36), Some(0xf));
        assert_eq!(decoder.next(0x09), Some(0x62));
        assert_eq!(decoder.next(0x29), Some(0x69));
        assert_eq!(decoder.next(0x1b), None);
        assert_eq!(decoder.next(0x26), Some(0x6e));
    }
}