titanite 0.3.0

Client/Server Library for Gemini protocol with Titan support
Documentation
pub mod cgi_error;
pub mod general;
pub mod proxy_error;
pub mod server_unavailable;
pub mod slow_down;

pub use cgi_error::CgiError;
pub use general::General;
pub use proxy_error::ProxyError;
pub use server_unavailable::ServerUnavailable;
pub use slow_down::SlowDown;

use anyhow::{bail, Result};

pub enum Temporary {
    /// [General temporary failure](https://geminiprotocol.net/docs/protocol-specification.gmi#status-40)
    General(General),
    /// [Server unavailable](https://geminiprotocol.net/docs/protocol-specification.gmi#status-41-server-unavailable)
    ServerUnavailable(ServerUnavailable),
    /// [CGI error](https://geminiprotocol.net/docs/protocol-specification.gmi#status-42-cgi-error)
    CgiError(CgiError),
    /// [Proxy error](https://geminiprotocol.net/docs/protocol-specification.gmi#status-43-proxy-error)
    ProxyError(ProxyError),
    /// [Slow down](https://geminiprotocol.net/docs/protocol-specification.gmi#status-44-slow-down)
    SlowDown(SlowDown),
}

impl Temporary {
    pub fn from_bytes(buffer: &[u8]) -> Result<Self> {
        if buffer.first().is_none_or(|b| *b != b'4') {
            bail!("Unexpected first byte")
        }
        match buffer.get(1) {
            Some(byte) => Ok(match byte {
                b'0' => Self::General(General::from_bytes(buffer)?),
                b'1' => Self::ServerUnavailable(ServerUnavailable::from_bytes(buffer)?),
                b'2' => Self::CgiError(CgiError::from_bytes(buffer)?),
                b'3' => Self::ProxyError(ProxyError::from_bytes(buffer)?),
                b'4' => Self::SlowDown(SlowDown::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::ServerUnavailable(this) => this.into_bytes(),
            Self::CgiError(this) => this.into_bytes(),
            Self::ProxyError(this) => this.into_bytes(),
            Self::SlowDown(this) => this.into_bytes(),
        }
    }
}

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

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

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

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

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

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