titanite 0.3.0

Client/Server Library for Gemini protocol with Titan support
Documentation
pub mod permanent;
pub mod temporary;

pub use permanent::Permanent;
pub use temporary::Temporary;

use anyhow::{bail, Result};

/// [Redirect](https://geminiprotocol.net/docs/protocol-specification.gmi#redirection)
pub enum Redirect {
    Permanent(Permanent),
    Temporary(Temporary),
}

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

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

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

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

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