hyper 0.3.2

A modern HTTP library.
//! HTTP status codes
use std::fmt;
use std::num::{FromPrimitive, ToPrimitive};
use std::cmp::Ordering;

// shamelessly lifted from Teepee. I tried a few schemes, this really
// does seem like the best. Improved scheme to support arbitary status codes.

/// An HTTP status code (`status-code` in RFC 7230 et al.).
///
/// This enum contains all common status codes and an Unregistered
/// extension variant. It allows status codes in the range [0, 65535], as any
/// `u16` integer may be used as a status code for XHR requests. It is
/// recommended to only use values between [100, 599], since only these are
/// defined as valid status codes with a status class by HTTP.
///
/// If you encounter a status code that you do not know how to deal with, you
/// should treat it as the `x00` status code—e.g. for code 123, treat it as
/// 100 (Continue). This can be achieved with
/// `self.class().default_code()`:
///
/// ```rust
/// # use std::num::FromPrimitive;
/// # use hyper::status::StatusCode;
/// let statusopt: Option<StatusCode> = FromPrimitive::from_u16(137u16);
/// assert_eq!(statusopt.unwrap().class().default_code(), StatusCode::Continue);
/// ```
///
/// IANA maintain the [Hypertext Transfer Protocol (HTTP) Status Code
/// Registry](http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml) which is
/// the source for this enum (with one exception, 418 I'm a teapot, which is
/// inexplicably not in the register).
pub enum StatusCode {
    /// 100 Continue
    /// [[RFC7231, Section 6.2.1](https://tools.ietf.org/html/rfc7231#section-6.2.1)]
    Continue,
    /// 101 Switching Protocols
    /// [[RFC7231, Section 6.2.2](https://tools.ietf.org/html/rfc7231#section-6.2.2)]
    SwitchingProtocols,
    /// 102 Processing
    /// [[RFC2518](https://tools.ietf.org/html/rfc2518)]
    Processing,

    /// 200 OK
    /// [[RFC7231, Section 6.3.1](https://tools.ietf.org/html/rfc7231#section-6.3.1)]
    Ok,
    /// 201 Created
    /// [[RFC7231, Section 6.3.2](https://tools.ietf.org/html/rfc7231#section-6.3.2)]
    Created,
    /// 202 Accepted
    /// [[RFC7231, Section 6.3.3](https://tools.ietf.org/html/rfc7231#section-6.3.3)]
    Accepted,
    /// 203 Non-Authoritative Information
    /// [[RFC7231, Section 6.3.4](https://tools.ietf.org/html/rfc7231#section-6.3.4)]
    NonAuthoritativeInformation,
    /// 204 No Content
    /// [[RFC7231, Section 6.3.5](https://tools.ietf.org/html/rfc7231#section-6.3.5)]
    NoContent,
    /// 205 Reset Content
    /// [[RFC7231, Section 6.3.6](https://tools.ietf.org/html/rfc7231#section-6.3.6)]
    ResetContent,
    /// 206 Partial Content
    /// [[RFC7233, Section 4.1](https://tools.ietf.org/html/rfc7233#section-4.1)]
    PartialContent,
    /// 207 Multi-Status
    /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
    MultiStatus,
    /// 208 Already Reported
    /// [[RFC5842](https://tools.ietf.org/html/rfc5842)]
    AlreadyReported,

    /// 226 IM Used
    /// [[RFC3229](https://tools.ietf.org/html/rfc3229)]
    ImUsed,

    /// 300 Multiple Choices
    /// [[RFC7231, Section 6.4.1](https://tools.ietf.org/html/rfc7231#section-6.4.1)]
    MultipleChoices,
    /// 301 Moved Permanently
    /// [[RFC7231, Section 6.4.2](https://tools.ietf.org/html/rfc7231#section-6.4.2)]
    MovedPermanently,
    /// 302 Found
    /// [[RFC7231, Section 6.4.3](https://tools.ietf.org/html/rfc7231#section-6.4.3)]
    Found,
    /// 303 See Other
    /// [[RFC7231, Section 6.4.4](https://tools.ietf.org/html/rfc7231#section-6.4.4)]
    SeeOther,
    /// 304 Not Modified
    /// [[RFC7232, Section 4.1](https://tools.ietf.org/html/rfc7232#section-4.1)]
    NotModified,
    /// 305 Use Proxy
    /// [[RFC7231, Section 6.4.5](https://tools.ietf.org/html/rfc7231#section-6.4.5)]
    UseProxy,
    /// 307 Temporary Redirect
    /// [[RFC7231, Section 6.4.7](https://tools.ietf.org/html/rfc7231#section-6.4.7)]
    TemporaryRedirect,
    /// 308 Permanent Redirect
    /// [[RFC7238](https://tools.ietf.org/html/rfc7238)]
    PermanentRedirect,

    /// 400 Bad Request
    /// [[RFC7231, Section 6.5.1](https://tools.ietf.org/html/rfc7231#section-6.5.1)]
    BadRequest,
    /// 401 Unauthorized
    /// [[RFC7235, Section 3.1](https://tools.ietf.org/html/rfc7235#section-3.1)]
    Unauthorized,
    /// 402 Payment Required
    /// [[RFC7231, Section 6.5.2](https://tools.ietf.org/html/rfc7231#section-6.5.2)]
    PaymentRequired,
    /// 403 Forbidden
    /// [[RFC7231, Section 6.5.3](https://tools.ietf.org/html/rfc7231#section-6.5.3)]
    Forbidden,
    /// 404 Not Found
    /// [[RFC7231, Section 6.5.4](https://tools.ietf.org/html/rfc7231#section-6.5.4)]
    NotFound,
    /// 405 Method Not Allowed
    /// [[RFC7231, Section 6.5.5](https://tools.ietf.org/html/rfc7231#section-6.5.5)]
    MethodNotAllowed,
    /// 406 Not Acceptable
    /// [[RFC7231, Section 6.5.6](https://tools.ietf.org/html/rfc7231#section-6.5.6)]
    NotAcceptable,
    /// 407 Proxy Authentication Required
    /// [[RFC7235, Section 3.2](https://tools.ietf.org/html/rfc7235#section-3.2)]
    ProxyAuthenticationRequired,
    /// 408 Request Timeout
    /// [[RFC7231, Section 6.5.7](https://tools.ietf.org/html/rfc7231#section-6.5.7)]
    RequestTimeout,
    /// 409 Conflict
    /// [[RFC7231, Section 6.5.8](https://tools.ietf.org/html/rfc7231#section-6.5.8)]
    Conflict,
    /// 410 Gone
    /// [[RFC7231, Section 6.5.9](https://tools.ietf.org/html/rfc7231#section-6.5.9)]
    Gone,
    /// 411 Length Required
    /// [[RFC7231, Section 6.5.10](https://tools.ietf.org/html/rfc7231#section-6.5.10)]
    LengthRequired,
    /// 412 Precondition Failed
    /// [[RFC7232, Section 4.2](https://tools.ietf.org/html/rfc7232#section-4.2)]
    PreconditionFailed,
    /// 413 Payload Too Large
    /// [[RFC7231, Section 6.5.11](https://tools.ietf.org/html/rfc7231#section-6.5.11)]
    PayloadTooLarge,
    /// 414 URI Too Long
    /// [[RFC7231, Section 6.5.12](https://tools.ietf.org/html/rfc7231#section-6.5.12)]
    UriTooLong,
    /// 415 Unsupported Media Type
    /// [[RFC7231, Section 6.5.13](https://tools.ietf.org/html/rfc7231#section-6.5.13)]
    UnsupportedMediaType,
    /// 416 Range Not Satisfiable
    /// [[RFC7233, Section 4.4](https://tools.ietf.org/html/rfc7233#section-4.4)]
    RangeNotSatisfiable,
    /// 417 Expectation Failed
    /// [[RFC7231, Section 6.5.14](https://tools.ietf.org/html/rfc7231#section-6.5.14)]
    ExpectationFailed,
    /// 418 I'm a teapot
    /// [curiously, not registered by IANA, but [RFC2324](https://tools.ietf.org/html/rfc2324)]
    ImATeapot,

    /// 422 Unprocessable Entity
    /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
    UnprocessableEntity,
    /// 423 Locked
    /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
    Locked,
    /// 424 Failed Dependency
    /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
    FailedDependency,

    /// 426 Upgrade Required
    /// [[RFC7231, Section 6.5.15](https://tools.ietf.org/html/rfc7231#section-6.5.15)]
    UpgradeRequired,

    /// 428 Precondition Required
    /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
    PreconditionRequired,
    /// 429 Too Many Requests
    /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
    TooManyRequests,

    /// 431 Request Header Fields Too Large
    /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
    RequestHeaderFieldsTooLarge,

    /// 500 Internal Server Error
    /// [[RFC7231, Section 6.6.1](https://tools.ietf.org/html/rfc7231#section-6.6.1)]
    InternalServerError,
    /// 501 Not Implemented
    /// [[RFC7231, Section 6.6.2](https://tools.ietf.org/html/rfc7231#section-6.6.2)]
    NotImplemented,
    /// 502 Bad Gateway
    /// [[RFC7231, Section 6.6.3](https://tools.ietf.org/html/rfc7231#section-6.6.3)]
    BadGateway,
    /// 503 Service Unavailable
    /// [[RFC7231, Section 6.6.4](https://tools.ietf.org/html/rfc7231#section-6.6.4)]
    ServiceUnavailable,
    /// 504 Gateway Timeout
    /// [[RFC7231, Section 6.6.5](https://tools.ietf.org/html/rfc7231#section-6.6.5)]
    GatewayTimeout,
    /// 505 HTTP Version Not Supported
    /// [[RFC7231, Section 6.6.6](https://tools.ietf.org/html/rfc7231#section-6.6.6)]
    HttpVersionNotSupported,
    /// 506 Variant Also Negotiates
    /// [[RFC2295](https://tools.ietf.org/html/rfc2295)]
    VariantAlsoNegotiates,
    /// 507 Insufficient Storage
    /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
    InsufficientStorage,
    /// 508 Loop Detected
    /// [[RFC5842](https://tools.ietf.org/html/rfc5842)]
    LoopDetected,

    /// 510 Not Extended
    /// [[RFC2774](https://tools.ietf.org/html/rfc2774)]
    NotExtended,
    /// 511 Network Authentication Required
    /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
    NetworkAuthenticationRequired,

    /// A status code not in the IANA HTTP status code registry or very well known
    // `ImATeapot` is not registered.
    Unregistered(u16),
}

impl StatusCode {

    /// Get the standardised `reason-phrase` for this status code.
    ///
    /// This is mostly here for servers writing responses, but could potentially have application
    /// at other times.
    ///
    /// The reason phrase is defined as being exclusively for human readers. You should avoid
    /// deriving any meaning from it at all costs.
    ///
    /// Bear in mind also that in HTTP/2.0 the reason phrase is abolished from transmission, and so
    /// this canonical reason phrase really is the only reason phrase you’ll find.
    pub fn canonical_reason(&self) -> Option<&'static str> {
        match *self {
            StatusCode::Continue => Some("Continue"),
            StatusCode::SwitchingProtocols => Some("Switching Protocols"),
            StatusCode::Processing => Some("Processing"),

            StatusCode::Ok => Some("OK"),
            StatusCode::Created => Some("Created"),
            StatusCode::Accepted => Some("Accepted"),
            StatusCode::NonAuthoritativeInformation => Some("Non-Authoritative Information"),
            StatusCode::NoContent => Some("No Content"),
            StatusCode::ResetContent => Some("Reset Content"),
            StatusCode::PartialContent => Some("Partial Content"),
            StatusCode::MultiStatus => Some("Multi-Status"),
            StatusCode::AlreadyReported => Some("Already Reported"),

            StatusCode::ImUsed => Some("IM Used"),

            StatusCode::MultipleChoices => Some("Multiple Choices"),
            StatusCode::MovedPermanently => Some("Moved Permanently"),
            StatusCode::Found => Some("Found"),
            StatusCode::SeeOther => Some("See Other"),
            StatusCode::NotModified => Some("Not Modified"),
            StatusCode::UseProxy => Some("Use Proxy"),

            StatusCode::TemporaryRedirect => Some("Temporary Redirect"),
            StatusCode::PermanentRedirect => Some("Permanent Redirect"),

            StatusCode::BadRequest => Some("Bad Request"),
            StatusCode::Unauthorized => Some("Unauthorized"),
            StatusCode::PaymentRequired => Some("Payment Required"),
            StatusCode::Forbidden => Some("Forbidden"),
            StatusCode::NotFound => Some("Not Found"),
            StatusCode::MethodNotAllowed => Some("Method Not Allowed"),
            StatusCode::NotAcceptable => Some("Not Acceptable"),
            StatusCode::ProxyAuthenticationRequired => Some("Proxy Authentication Required"),
            StatusCode::RequestTimeout => Some("Request Timeout"),
            StatusCode::Conflict => Some("Conflict"),
            StatusCode::Gone => Some("Gone"),
            StatusCode::LengthRequired => Some("Length Required"),
            StatusCode::PreconditionFailed => Some("Precondition Failed"),
            StatusCode::PayloadTooLarge => Some("Payload Too Large"),
            StatusCode::UriTooLong => Some("URI Too Long"),
            StatusCode::UnsupportedMediaType => Some("Unsupported Media Type"),
            StatusCode::RangeNotSatisfiable => Some("Range Not Satisfiable"),
            StatusCode::ExpectationFailed => Some("Expectation Failed"),
            StatusCode::ImATeapot => Some("I'm a teapot"),

            StatusCode::UnprocessableEntity => Some("Unprocessable Entity"),
            StatusCode::Locked => Some("Locked"),
            StatusCode::FailedDependency => Some("Failed Dependency"),

            StatusCode::UpgradeRequired => Some("Upgrade Required"),

            StatusCode::PreconditionRequired => Some("Precondition Required"),
            StatusCode::TooManyRequests => Some("Too Many Requests"),

            StatusCode::RequestHeaderFieldsTooLarge => Some("Request Header Fields Too Large"),

            StatusCode::InternalServerError => Some("Internal Server Error"),
            StatusCode::NotImplemented => Some("Not Implemented"),
            StatusCode::BadGateway => Some("Bad Gateway"),
            StatusCode::ServiceUnavailable => Some("Service Unavailable"),
            StatusCode::GatewayTimeout => Some("Gateway Timeout"),
            StatusCode::HttpVersionNotSupported => Some("HTTP Version Not Supported"),
            StatusCode::VariantAlsoNegotiates => Some("Variant Also Negotiates"),
            StatusCode::InsufficientStorage => Some("Insufficient Storage"),
            StatusCode::LoopDetected => Some("Loop Detected"),

            StatusCode::NotExtended => Some("Not Extended"),
            StatusCode::NetworkAuthenticationRequired => Some("Network Authentication Required"),
            _ => None
        }
    }

    /// Determine the class of a status code, based on its first digit.
    pub fn class(&self) -> StatusClass {
        match self.to_u16().unwrap() {
            100...199 => StatusClass::Informational,
            200...299 => StatusClass::Success,
            300...399 => StatusClass::Redirection,
            400...499 => StatusClass::ClientError,
            500...599 => StatusClass::ServerError,
            _ => StatusClass::NoClass,
        }
    }

    /// Check if class is Informational.
    pub fn is_informational(&self) -> bool {
        self.class() == StatusClass::Informational
    }

    /// Check if class is Success.
    pub fn is_success(&self) -> bool {
        self.class() == StatusClass::Success
    }

    /// Check if class is Redirection.
    pub fn is_redirection(&self) -> bool {
        self.class() == StatusClass::Redirection
    }

    /// Check if class is ClientError.
    pub fn is_client_error(&self) -> bool {
        self.class() == StatusClass::ClientError
    }

    /// Check if class is ServerError.
    pub fn is_server_error(&self) -> bool {
        self.class() == StatusClass::ServerError
    }

    /// Check if class is NoClass
    pub fn is_strange_status(&self) -> bool {
        self.class() == StatusClass::NoClass
    }
}

impl Copy for StatusCode {}

/// Formats the status code, *including* the canonical reason.
///
/// ```rust
/// # use hyper::status::StatusCode::{ImATeapot, Unregistered};
/// assert_eq!(format!("{}", ImATeapot).as_slice(),
///            "418 I'm a teapot");
/// assert_eq!(format!("{}", Unregistered(123)).as_slice(),
///            "123 <unknown status code>");
/// ```
///
/// If you wish to just include the number, convert to `u16` instead:
///
/// ```rust
/// # use std::num::ToPrimitive;
/// # use hyper::status::StatusCode::{ImATeapot, Unregistered};
/// assert_eq!(format!("{}", ImATeapot.to_u16().unwrap()).as_slice(), "418");
/// assert_eq!(format!("{}", Unregistered(123).to_u16().unwrap()).as_slice(), "123");
/// ```
impl fmt::Display for StatusCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {}", self.to_u16().unwrap(),
               self.canonical_reason().unwrap_or("<unknown status code>"))
    }
}

impl fmt::Debug for StatusCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match *self {
            StatusCode::Continue => "Continue",
            StatusCode::SwitchingProtocols => "SwitchingProtocols",
            StatusCode::Processing => "Processing",

            StatusCode::Ok => "Ok",
            StatusCode::Created => "Created",
            StatusCode::Accepted => "Accepted",
            StatusCode::NonAuthoritativeInformation => "NonAuthoritativeInformation",
            StatusCode::NoContent => "NoContent",
            StatusCode::ResetContent => "ResetContent",
            StatusCode::PartialContent => "PartialContent",
            StatusCode::MultiStatus => "MultiStatus",
            StatusCode::AlreadyReported => "AlreadyReported",

            StatusCode::ImUsed => "ImUsed",

            StatusCode::MultipleChoices => "MultipleChoices",
            StatusCode::MovedPermanently => "MovedPermanently",
            StatusCode::Found => "Found",
            StatusCode::SeeOther => "SeeOther",
            StatusCode::NotModified => "NotModified",
            StatusCode::UseProxy => "UseProxy",

            StatusCode::TemporaryRedirect => "TemporaryRedirect",
            StatusCode::PermanentRedirect => "PermanentRedirect",

            StatusCode::BadRequest => "BadRequest",
            StatusCode::Unauthorized => "Unauthorized",
            StatusCode::PaymentRequired => "PaymentRequired",
            StatusCode::Forbidden => "Forbidden",
            StatusCode::NotFound => "NotFound",
            StatusCode::MethodNotAllowed => "MethodNotAllowed",
            StatusCode::NotAcceptable => "NotAcceptable",
            StatusCode::ProxyAuthenticationRequired => "ProxyAuthenticationRequired",
            StatusCode::RequestTimeout => "RequestTimeout",
            StatusCode::Conflict => "Conflict",
            StatusCode::Gone => "Gone",
            StatusCode::LengthRequired => "LengthRequired",
            StatusCode::PreconditionFailed => "PreconditionFailed",
            StatusCode::PayloadTooLarge => "PayloadTooLarge",
            StatusCode::UriTooLong => "UriTooLong",
            StatusCode::UnsupportedMediaType => "UnsupportedMediaType",
            StatusCode::RangeNotSatisfiable => "RangeNotSatisfiable",
            StatusCode::ExpectationFailed => "ExpectationFailed",
            StatusCode::ImATeapot => "ImATeapot",

            StatusCode::UnprocessableEntity => "UnprocessableEntity",
            StatusCode::Locked => "Locked",
            StatusCode::FailedDependency => "FailedDependency",

            StatusCode::UpgradeRequired => "UpgradeRequired",

            StatusCode::PreconditionRequired => "PreconditionRequired",
            StatusCode::TooManyRequests => "TooManyRequests",

            StatusCode::RequestHeaderFieldsTooLarge => "RequestHeaderFieldsTooLarge",

            StatusCode::InternalServerError => "InternalServerError",
            StatusCode::NotImplemented => "NotImplemented",
            StatusCode::BadGateway => "BadGateway",
            StatusCode::ServiceUnavailable => "ServiceUnavailable",
            StatusCode::GatewayTimeout => "GatewayTimeout",
            StatusCode::HttpVersionNotSupported => "HttpVersionNotSupported",
            StatusCode::VariantAlsoNegotiates => "VariantAlsoNegotiates",
            StatusCode::InsufficientStorage => "InsufficientStorage",
            StatusCode::LoopDetected => "LoopDetected",

            StatusCode::NotExtended => "NotExtended",
            StatusCode::NetworkAuthenticationRequired => "NetworkAuthenticationRequired",
            StatusCode::Unregistered(ref code) => {
                return write!(f, "Unregistered({})", code);
            }
        };
        f.write_str(s)
    }
}

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

impl Eq for StatusCode {}

impl Clone for StatusCode {
    #[inline]
    fn clone(&self) -> StatusCode {
        *self
    }
}

impl FromPrimitive for StatusCode {
    fn from_i64(n: i64) -> Option<StatusCode> {
        if n < 0 {
            None
        } else {
            FromPrimitive::from_u64(n as u64)
        }
    }

    fn from_u64(n: u64) -> Option<StatusCode> {
        if n > 65535 {
            None
        } else {
            Some(match n {
                100 => StatusCode::Continue,
                101 => StatusCode::SwitchingProtocols,
                102 => StatusCode::Processing,
                200 => StatusCode::Ok,
                201 => StatusCode::Created,
                202 => StatusCode::Accepted,
                203 => StatusCode::NonAuthoritativeInformation,
                204 => StatusCode::NoContent,
                205 => StatusCode::ResetContent,
                206 => StatusCode::PartialContent,
                207 => StatusCode::MultiStatus,
                208 => StatusCode::AlreadyReported,
                226 => StatusCode::ImUsed,
                300 => StatusCode::MultipleChoices,
                301 => StatusCode::MovedPermanently,
                302 => StatusCode::Found,
                303 => StatusCode::SeeOther,
                304 => StatusCode::NotModified,
                305 => StatusCode::UseProxy,
                307 => StatusCode::TemporaryRedirect,
                308 => StatusCode::PermanentRedirect,
                400 => StatusCode::BadRequest,
                401 => StatusCode::Unauthorized,
                402 => StatusCode::PaymentRequired,
                403 => StatusCode::Forbidden,
                404 => StatusCode::NotFound,
                405 => StatusCode::MethodNotAllowed,
                406 => StatusCode::NotAcceptable,
                407 => StatusCode::ProxyAuthenticationRequired,
                408 => StatusCode::RequestTimeout,
                409 => StatusCode::Conflict,
                410 => StatusCode::Gone,
                411 => StatusCode::LengthRequired,
                412 => StatusCode::PreconditionFailed,
                413 => StatusCode::PayloadTooLarge,
                414 => StatusCode::UriTooLong,
                415 => StatusCode::UnsupportedMediaType,
                416 => StatusCode::RangeNotSatisfiable,
                417 => StatusCode::ExpectationFailed,
                418 => StatusCode::ImATeapot,
                422 => StatusCode::UnprocessableEntity,
                423 => StatusCode::Locked,
                424 => StatusCode::FailedDependency,
                426 => StatusCode::UpgradeRequired,
                428 => StatusCode::PreconditionRequired,
                429 => StatusCode::TooManyRequests,
                431 => StatusCode::RequestHeaderFieldsTooLarge,
                500 => StatusCode::InternalServerError,
                501 => StatusCode::NotImplemented,
                502 => StatusCode::BadGateway,
                503 => StatusCode::ServiceUnavailable,
                504 => StatusCode::GatewayTimeout,
                505 => StatusCode::HttpVersionNotSupported,
                506 => StatusCode::VariantAlsoNegotiates,
                507 => StatusCode::InsufficientStorage,
                508 => StatusCode::LoopDetected,
                510 => StatusCode::NotExtended,
                511 => StatusCode::NetworkAuthenticationRequired,
                _ => StatusCode::Unregistered(n as u16),
            })
        }
    }
}

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

impl Ord for StatusCode {
    #[inline]
    fn cmp(&self, other: &StatusCode) -> Ordering {
        if *self < *other {
            Ordering::Less
        } else if *self > *other {
            Ordering::Greater
        } else {
            Ordering::Equal
        }
    }
}

impl ToPrimitive for StatusCode {
    fn to_i64(&self) -> Option<i64> {
        Some(self.to_u64().unwrap() as i64)
    }

    fn to_u64(&self) -> Option<u64> {
        Some(match *self {
            StatusCode::Continue => 100,
            StatusCode::SwitchingProtocols => 101,
            StatusCode::Processing => 102,
            StatusCode::Ok => 200,
            StatusCode::Created => 201,
            StatusCode::Accepted => 202,
            StatusCode::NonAuthoritativeInformation => 203,
            StatusCode::NoContent => 204,
            StatusCode::ResetContent => 205,
            StatusCode::PartialContent => 206,
            StatusCode::MultiStatus => 207,
            StatusCode::AlreadyReported => 208,
            StatusCode::ImUsed => 226,
            StatusCode::MultipleChoices => 300,
            StatusCode::MovedPermanently => 301,
            StatusCode::Found => 302,
            StatusCode::SeeOther => 303,
            StatusCode::NotModified => 304,
            StatusCode::UseProxy => 305,
            StatusCode::TemporaryRedirect => 307,
            StatusCode::PermanentRedirect => 308,
            StatusCode::BadRequest => 400,
            StatusCode::Unauthorized => 401,
            StatusCode::PaymentRequired => 402,
            StatusCode::Forbidden => 403,
            StatusCode::NotFound => 404,
            StatusCode::MethodNotAllowed => 405,
            StatusCode::NotAcceptable => 406,
            StatusCode::ProxyAuthenticationRequired => 407,
            StatusCode::RequestTimeout => 408,
            StatusCode::Conflict => 409,
            StatusCode::Gone => 410,
            StatusCode::LengthRequired => 411,
            StatusCode::PreconditionFailed => 412,
            StatusCode::PayloadTooLarge => 413,
            StatusCode::UriTooLong => 414,
            StatusCode::UnsupportedMediaType => 415,
            StatusCode::RangeNotSatisfiable => 416,
            StatusCode::ExpectationFailed => 417,
            StatusCode::ImATeapot => 418,
            StatusCode::UnprocessableEntity => 422,
            StatusCode::Locked => 423,
            StatusCode::FailedDependency => 424,
            StatusCode::UpgradeRequired => 426,
            StatusCode::PreconditionRequired => 428,
            StatusCode::TooManyRequests => 429,
            StatusCode::RequestHeaderFieldsTooLarge => 431,
            StatusCode::InternalServerError => 500,
            StatusCode::NotImplemented => 501,
            StatusCode::BadGateway => 502,
            StatusCode::ServiceUnavailable => 503,
            StatusCode::GatewayTimeout => 504,
            StatusCode::HttpVersionNotSupported => 505,
            StatusCode::VariantAlsoNegotiates => 506,
            StatusCode::InsufficientStorage => 507,
            StatusCode::LoopDetected => 508,
            StatusCode::NotExtended => 510,
            StatusCode::NetworkAuthenticationRequired => 511,
            StatusCode::Unregistered(n) => n,
        } as u64)
    }
}

/// The class of an HTTP `status-code`.
///
/// [RFC 7231, section 6 (Response Status Codes)](https://tools.ietf.org/html/rfc7231#section-6):
///
/// > The first digit of the status-code defines the class of response.
/// > The last two digits do not have any categorization role.
///
/// And:
///
/// > HTTP status codes are extensible.  HTTP clients are not required to
/// > understand the meaning of all registered status codes, though such
/// > understanding is obviously desirable.  However, a client MUST
/// > understand the class of any status code, as indicated by the first
/// > digit, and treat an unrecognized status code as being equivalent to
/// > the x00 status code of that class, with the exception that a
/// > recipient MUST NOT cache a response with an unrecognized status code.
/// >
/// > For example, if an unrecognized status code of 471 is received by a
/// > client, the client can assume that there was something wrong with its
/// > request and treat the response as if it had received a 400 (Bad
/// > Request) status code.  The response message will usually contain a
/// > representation that explains the status.
///
/// This can be used in cases where a status code’s meaning is unknown, also,
/// to get the appropriate *category* of status.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
pub enum StatusClass {
    /// 1xx (Informational): The request was received, continuing process
    Informational,

    /// 2xx (Success): The request was successfully received, understood, and accepted
    Success,

    /// 3xx (Redirection): Further action needs to be taken in order to complete the request
    Redirection,

    /// 4xx (Client Error): The request contains bad syntax or cannot be fulfilled
    ClientError,

    /// 5xx (Server Error): The server failed to fulfill an apparently valid request
    ServerError,

    /// A status code lower than 100 or higher than 599. These codes do no belong to any class.
    NoClass,
}

impl StatusClass {
    /// Get the default status code for the class.
    ///
    /// This produces the x00 status code; thus, for `ClientError` (4xx), for
    /// example, this will produce `BadRequest` (400):
    ///
    /// ```rust
    /// # use hyper::status::StatusClass::ClientError;
    /// # use hyper::status::StatusCode::BadRequest;
    /// assert_eq!(ClientError.default_code(), BadRequest);
    /// ```
    ///
    /// The use for this is outlined in [RFC 7231, section 6 (Response Status
    /// Codes)](https://tools.ietf.org/html/rfc7231#section-6):
    ///
    /// > HTTP status codes are extensible.  HTTP clients are not required to
    /// > understand the meaning of all registered status codes, though such
    /// > understanding is obviously desirable.  However, a client MUST
    /// > understand the class of any status code, as indicated by the first
    /// > digit, and treat an unrecognized status code as being equivalent to
    /// > the x00 status code of that class, with the exception that a
    /// > recipient MUST NOT cache a response with an unrecognized status code.
    /// >
    /// > For example, if an unrecognized status code of 471 is received by a
    /// > client, the client can assume that there was something wrong with its
    /// > request and treat the response as if it had received a 400 (Bad
    /// > Request) status code.  The response message will usually contain a
    /// > representation that explains the status.
    ///
    /// This is demonstrated thusly:
    ///
    /// ```rust
    /// # use hyper::status::StatusCode::{Unregistered, BadRequest};
    /// // Suppose we have received this status code.
    /// // You will never directly create an unregistered status code.
    /// let status = Unregistered(471);
    ///
    /// // Uh oh! Don’t know what to do with it.
    /// // Let’s fall back to the default:
    /// let status = status.class().default_code();
    ///
    /// // And look! That is 400 Bad Request.
    /// assert_eq!(status, BadRequest);
    /// // So now let’s treat it as that.
    /// ```
    /// All status codes that do not map to an existing status class are matched
    /// by a `NoClass`, variant that resolves to 200 (Ok) as default code.
    /// This is a common handling for unknown status codes in major browsers.
    pub fn default_code(&self) -> StatusCode {
        match *self {
            StatusClass::Informational => StatusCode::Continue,
            StatusClass::Success => StatusCode::Ok,
            StatusClass::Redirection => StatusCode::MultipleChoices,
            StatusClass::ClientError => StatusCode::BadRequest,
            StatusClass::ServerError => StatusCode::InternalServerError,
            StatusClass::NoClass => StatusCode::Ok,
        }
    }
}

impl ToPrimitive for StatusClass {
    fn to_i64(&self) -> Option<i64> {
        Some(self.to_u64().unwrap() as i64)
    }

    fn to_u64(&self) -> Option<u64> {
        Some(match *self {
            StatusClass::Informational => 100,
            StatusClass::Success => 200,
            StatusClass::Redirection => 300,
            StatusClass::ClientError => 400,
            StatusClass::ServerError => 500,
            StatusClass::NoClass => 200,
        })
    }
}