titanite 0.2.0

Client/Server Library for Gemini protocol with Titan support
Documentation
pub mod certificate;
pub mod failure;
pub mod input;
pub mod redirect;
pub mod success;

pub use certificate::Certificate;
pub use failure::Failure;
pub use input::Input;
pub use redirect::Redirect;
pub use success::Success;

use anyhow::{bail, Result};

/// [Gemini](https://geminiprotocol.net/docs/protocol-specification.gmi) source
pub enum Response<'a> {
    Certificate(Certificate),
    Failure(Failure),
    Input(Input),
    Redirect(Redirect),
    Success(Success<'a>),
}

impl<'a> Response<'a> {
    pub fn from_bytes(buffer: &'a [u8]) -> Result<Self> {
        match buffer.first() {
            Some(byte) => Ok(match byte {
                b'1' => Self::Input(Input::from_bytes(buffer)?),
                b'2' => Self::Success(Success::from_bytes(buffer)?),
                b'3' => Self::Redirect(Redirect::from_bytes(buffer)?),
                b'4' | b'5' => Self::Failure(Failure::from_bytes(buffer)?),
                b'6' => Self::Certificate(Certificate::from_bytes(buffer)?),
                b => bail!("Unspecified header byte: {b}"),
            }),
            None => bail!("Empty source"),
        }
    }

    pub fn into_bytes(self) -> Vec<u8> {
        match self {
            Self::Certificate(this) => this.into_bytes(),
            Self::Failure(this) => this.into_bytes(),
            Self::Input(this) => this.into_bytes(),
            Self::Redirect(this) => this.into_bytes(),
            Self::Success(this) => this.into_bytes(),
        }
    }
}

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

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

        match target {
            Response::Input(ref this) => match this {
                Input::Sensitive(this) => assert_eq!(this.message, Some("message".to_string())),
                _ => panic!(),
            },
            _ => panic!(),
        }
        assert_eq!(target.into_bytes(), source.as_bytes());
    }
    // 20
    {
        let source = format!("20 text/gemini\r\ndata");
        let target = Response::from_bytes(source.as_bytes()).unwrap();

        match target {
            Response::Success(ref this) => match this {
                Success::Default(this) => {
                    assert_eq!(this.mime, "text/gemini".to_string());
                    assert_eq!(this.data, "data".as_bytes());
                }
            },
            _ => panic!(),
        }
        assert_eq!(target.into_bytes(), source.as_bytes());
    }
    // 30
    {
        let source = format!("30 target\r\n");
        let target = Response::from_bytes(source.as_bytes()).unwrap();

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

        match target {
            Response::Redirect(ref this) => match this {
                Redirect::Permanent(this) => assert_eq!(this.target, "target".to_string()),
                _ => panic!(),
            },
            _ => panic!(),
        }
        assert_eq!(target.into_bytes(), source.as_bytes());
    }
    // 4*
    {
        use failure::Temporary;
        // 40
        {
            let source = format!("40 message\r\n");
            let target = Response::from_bytes(source.as_bytes()).unwrap();

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

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

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

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

            match target {
                Response::Failure(ref this) => match this {
                    Failure::Temporary(this) => match this {
                        Temporary::SlowDown(this) => {
                            assert_eq!(this.message, Some("message".to_string()))
                        }
                        _ => panic!(),
                    },
                    _ => panic!(),
                },
                _ => panic!(),
            }
            assert_eq!(target.into_bytes(), source.as_bytes());
        }
    }
    // 5*
    {
        use failure::Permanent;
        // 50
        {
            let source = format!("50 message\r\n");
            let target = Response::from_bytes(source.as_bytes()).unwrap();

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

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

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

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

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

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

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

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