titanite 0.3.0

Client/Server Library for Gemini protocol with Titan support
Documentation
pub mod expected;
pub mod not_authorized;
pub mod not_valid;

pub use expected::Expected;
pub use not_authorized::NotAuthorized;
pub use not_valid::NotValid;

use anyhow::{bail, Result};

/// [Client certificates](https://geminiprotocol.net/docs/protocol-specification.gmi#client-certificates)
pub enum Certificate {
    Expected(Expected),
    NotAuthorized(NotAuthorized),
    NotValid(NotValid),
}

impl Certificate {
    pub fn from_bytes(buffer: &[u8]) -> Result<Self> {
        if buffer.first().is_none_or(|b| *b != b'6') {
            bail!("Unexpected first byte")
        }
        match buffer.get(1) {
            Some(byte) => Ok(match byte {
                b'0' => Self::Expected(Expected::from_bytes(buffer)?),
                b'1' => Self::NotAuthorized(NotAuthorized::from_bytes(buffer)?),
                b'2' => Self::NotValid(NotValid::from_bytes(buffer)?),
                b => bail!("Unexpected second byte: {b}"),
            }),
            None => bail!("Invalid request"),
        }
    }
    pub fn into_bytes(self) -> Vec<u8> {
        match self {
            Self::Expected(this) => this.into_bytes(),
            Self::NotAuthorized(this) => this.into_bytes(),
            Self::NotValid(this) => this.into_bytes(),
        }
    }
}

#[test]
fn test() {
    // 60
    let request = format!("60 message\r\n");
    let source = Certificate::from_bytes(request.as_bytes()).unwrap();

    match source {
        Certificate::Expected(ref this) => assert_eq!(this.message, Some("message".to_string())),
        _ => panic!(),
    }
    assert_eq!(source.into_bytes(), request.as_bytes());

    // 61
    let request = format!("61 message\r\n");
    let source = Certificate::from_bytes(request.as_bytes()).unwrap();

    match source {
        Certificate::NotAuthorized(ref this) => {
            assert_eq!(this.message, Some("message".to_string()))
        }
        _ => panic!(),
    }
    assert_eq!(source.into_bytes(), request.as_bytes());

    // 62
    let request = format!("62 message\r\n");
    let source = Certificate::from_bytes(request.as_bytes()).unwrap();

    match source {
        Certificate::NotValid(ref this) => assert_eq!(this.message, Some("message".to_string())),
        _ => panic!(),
    }
    assert_eq!(source.into_bytes(), request.as_bytes());
}