tick-encoding 0.1.4

A simple encoding scheme to encode binary data into ASCII strings
Documentation
use crate::{hex_bytes_to_byte, requires_escape, DecodeError};

#[derive(Debug, Default, Clone, Copy)]
pub enum Decoder {
    #[default]
    Ready,
    Finished,
    Tick,
    TickHalfHex(u8),
}

impl Decoder {
    #[inline]
    pub fn push(&mut self, input: Option<u8>) -> DecodeStatus {
        match (*self, input) {
            (Self::Finished, _) => DecodeStatus::Emit(None),
            (Self::Ready, Some(input)) => {
                if input == b'`' {
                    *self = Self::Tick;
                    DecodeStatus::NeedMore
                } else if requires_escape(input) {
                    *self = Self::Finished;
                    DecodeStatus::Emit(Some(Err(DecodeError::InvalidByte(input))))
                } else {
                    DecodeStatus::Emit(Some(Ok(input)))
                }
            }
            (Self::Ready, None) => {
                *self = Self::Finished;
                DecodeStatus::Emit(None)
            }
            (Self::Tick, Some(input)) => {
                if input == b'`' {
                    *self = Self::Ready;
                    DecodeStatus::Emit(Some(Ok(b'`')))
                } else {
                    *self = Self::TickHalfHex(input);
                    DecodeStatus::NeedMore
                }
            }
            (Self::Tick | Self::TickHalfHex(_), None) => {
                *self = Self::Finished;
                DecodeStatus::Emit(Some(Err(DecodeError::UnexpectedEnd)))
            }
            (Self::TickHalfHex(high), Some(low)) => {
                let byte_result = hex_bytes_to_byte(high, low);
                match byte_result {
                    Ok(byte) => {
                        *self = Self::Ready;
                        DecodeStatus::Emit(Some(Ok(byte)))
                    }
                    Err(error) => {
                        *self = Self::Finished;
                        DecodeStatus::Emit(Some(Err(error)))
                    }
                }
            }
        }
    }
}

pub enum DecodeStatus {
    NeedMore,
    Emit(Option<Result<u8, DecodeError>>),
}