safe_http 0.1.0-beta.4

Simple and safe HTTP types.
Documentation
use super::InvalidStatusCode;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StatusCode(u16);

impl StatusCode {
    #[inline]
    pub fn to_u16(self) -> u16 {
        self.0
    }

    #[inline]
    pub fn try_from_u16(code: u16) -> Result<Self, InvalidStatusCode> {
        if is_valid_status_code(code) {
            Ok(Self(code))
        } else {
            Err(InvalidStatusCode { code })
        }
    }

    pub(super) const fn internal_from_const_u16(code: u16) -> Self {
        if !is_valid_status_code(code) {
            #[allow(unconditional_panic, clippy::no_effect)]
            ([] as [u8; 0])[0]; // hack for panic in const fn,
        }
        Self(code)
    }

    pub fn is_informational(self) -> bool {
        matches!(self.to_u16(), 100..=199)
    }

    pub fn is_successful(self) -> bool {
        matches!(self.to_u16(), 200..=299)
    }

    pub fn is_redirection(self) -> bool {
        matches!(self.to_u16(), 300..=399)
    }

    pub fn is_client_error(self) -> bool {
        matches!(self.to_u16(), 400..=499)
    }

    pub fn is_server_error(self) -> bool {
        matches!(self.to_u16(), 500..=599)
    }
}

impl Default for StatusCode {
    fn default() -> Self {
        Self::OK
    }
}

impl From<StatusCode> for u16 {
    #[inline]
    fn from(s: StatusCode) -> Self {
        s.to_u16()
    }
}

impl PartialEq<u16> for StatusCode {
    #[inline]
    fn eq(&self, other: &u16) -> bool {
        self.to_u16().eq(other)
    }
}

impl PartialOrd<u16> for StatusCode {
    #[inline]
    fn partial_cmp(&self, other: &u16) -> Option<std::cmp::Ordering> {
        self.to_u16().partial_cmp(other)
    }
}

const fn is_valid_status_code(code: u16) -> bool {
    matches!(code, 100..=599)
}

#[cfg(test)]
mod tests {
    use super::*;
    use assert_matches::assert_matches;

    #[test]
    fn generated_constants_are_valid() {
        for constant in StatusCode::GENERATED_CONSTANTS.iter().map(|c| c.to_u16()) {
            // Invalid constants are a compile error if those constants are used.
            // So these asserts are just there to double check.
            assert_matches!(StatusCode::try_from_u16(constant), Ok(x) => assert_eq!(x, constant));
        }
    }
}