titanite 0.3.0

Client/Server Library for Gemini protocol with Titan support
Documentation
pub mod bad_request;
pub mod general;
pub mod gone;
pub mod not_found;
pub mod proxy_request_refused;

pub use bad_request::BadRequest;
pub use general::General;
pub use gone::Gone;
pub use not_found::NotFound;
pub use proxy_request_refused::ProxyRequestRefused;

use anyhow::{bail, Result};

/// [Permanent failure](https://geminiprotocol.net/docs/protocol-specification.gmi#permanent-failure)
pub enum Permanent {
    /// [General permanent failure](https://geminiprotocol.net/docs/protocol-specification.gmi#status-50)
    General(General),
    /// [Not found](https://geminiprotocol.net/docs/protocol-specification.gmi#status-51-not-found)
    NotFound(NotFound),
    /// [Gone](https://geminiprotocol.net/docs/protocol-specification.gmi#status-52-gone)
    Gone(Gone),
    /// [Proxy request refused](https://geminiprotocol.net/docs/protocol-specification.gmi#status-53-proxy-request-refused)
    ProxyRequestRefused(ProxyRequestRefused),
    /// [Bad request](https://geminiprotocol.net/docs/protocol-specification.gmi#status-59-bad-request)
    BadRequest(BadRequest),
}

impl Permanent {
    pub fn from_bytes(buffer: &[u8]) -> Result<Self> {
        if buffer.first().is_none_or(|b| *b != b'5') {
            bail!("Unexpected first byte")
        }
        match buffer.get(1) {
            Some(byte) => Ok(match byte {
                b'0' => Self::General(General::from_bytes(buffer)?),
                b'1' => Self::NotFound(NotFound::from_bytes(buffer)?),
                b'2' => Self::Gone(Gone::from_bytes(buffer)?),
                b'3' => Self::ProxyRequestRefused(ProxyRequestRefused::from_bytes(buffer)?),
                b'9' => Self::BadRequest(BadRequest::from_bytes(buffer)?),
                b => bail!("Unexpected second byte: {b}"),
            }),
            None => bail!("Invalid request"),
        }
    }
    pub fn into_bytes(self) -> Vec<u8> {
        match self {
            Self::General(this) => this.into_bytes(),
            Self::NotFound(this) => this.into_bytes(),
            Self::Gone(this) => this.into_bytes(),
            Self::ProxyRequestRefused(this) => this.into_bytes(),
            Self::BadRequest(this) => this.into_bytes(),
        }
    }
}

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

        match target {
            Permanent::General(ref this) => assert_eq!(this.message, Some("message".to_string())),
            _ => panic!(),
        }
        assert_eq!(target.into_bytes(), source.as_bytes());
    }
    // 51
    {
        let source = format!("51 message\r\n");
        let target = Permanent::from_bytes(source.as_bytes()).unwrap();

        match target {
            Permanent::NotFound(ref this) => assert_eq!(this.message, Some("message".to_string())),
            _ => panic!(),
        }
        assert_eq!(target.into_bytes(), source.as_bytes());
    }
    // 52
    {
        let source = format!("52 message\r\n");
        let target = Permanent::from_bytes(source.as_bytes()).unwrap();

        match target {
            Permanent::Gone(ref this) => assert_eq!(this.message, Some("message".to_string())),
            _ => panic!(),
        }
        assert_eq!(target.into_bytes(), source.as_bytes());
    }
    // 53
    {
        let source = format!("53 message\r\n");
        let target = Permanent::from_bytes(source.as_bytes()).unwrap();

        match target {
            Permanent::ProxyRequestRefused(ref this) => {
                assert_eq!(this.message, Some("message".to_string()))
            }
            _ => panic!(),
        }
        assert_eq!(target.into_bytes(), source.as_bytes());
    }
    // 59
    {
        let source = format!("59 message\r\n");
        let target = Permanent::from_bytes(source.as_bytes()).unwrap();

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