use self::Inner::*;
use std::convert::AsRef;
use std::error::Error;
use std::str::FromStr;
use std::convert::TryFrom;
use std::{fmt, str};
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Method(Inner);
pub struct InvalidMethod {
    _priv: (),
}
#[derive(Clone, PartialEq, Eq, Hash)]
enum Inner {
    Options,
    Get,
    Post,
    Put,
    Delete,
    Head,
    Trace,
    Connect,
    Patch,
    
    ExtensionInline([u8; MAX_INLINE], u8),
    
    ExtensionAllocated(Box<[u8]>),
}
const MAX_INLINE: usize = 15;
const METHOD_CHARS: [u8; 256] = [
    
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0',  b'!', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0',  b'*',  b'+', b'\0',  b'-',  b'.', b'\0',  b'0',  b'1', 
     b'2',  b'3',  b'4',  b'5',  b'6',  b'7',  b'8',  b'9', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0',  b'A',  b'B',  b'C',  b'D',  b'E', 
     b'F',  b'G',  b'H',  b'I',  b'J',  b'K',  b'L',  b'M',  b'N',  b'O', 
     b'P',  b'Q',  b'R',  b'S',  b'T',  b'U',  b'V',  b'W',  b'X',  b'Y', 
     b'Z', b'\0', b'\0', b'\0',  b'^',  b'_',  b'`',  b'a',  b'b',  b'c', 
     b'd',  b'e',  b'f',  b'g',  b'h',  b'i',  b'j',  b'k',  b'l',  b'm', 
     b'n',  b'o',  b'p',  b'q',  b'r',  b's',  b't',  b'u',  b'v',  b'w', 
     b'x',  b'y',  b'z', b'\0',  b'|', b'\0',  b'~', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', 
    b'\0', b'\0', b'\0', b'\0', b'\0', b'\0'                              
];
impl Method {
    
    pub const GET: Method = Method(Get);
    
    pub const POST: Method = Method(Post);
    
    pub const PUT: Method = Method(Put);
    
    pub const DELETE: Method = Method(Delete);
    
    pub const HEAD: Method = Method(Head);
    
    pub const OPTIONS: Method = Method(Options);
    
    pub const CONNECT: Method = Method(Connect);
    
    pub const PATCH: Method = Method(Patch);
    
    pub const TRACE: Method = Method(Trace);
    
    pub fn from_bytes(src: &[u8]) -> Result<Method, InvalidMethod> {
        match src.len() {
            0 => Err(InvalidMethod::new()),
            3 => match src {
                b"GET" => Ok(Method(Get)),
                b"PUT" => Ok(Method(Put)),
                _ => Method::extension_inline(src),
            },
            4 => match src {
                b"POST" => Ok(Method(Post)),
                b"HEAD" => Ok(Method(Head)),
                _ => Method::extension_inline(src),
            },
            5 => match src {
                b"PATCH" => Ok(Method(Patch)),
                b"TRACE" => Ok(Method(Trace)),
                _ => Method::extension_inline(src),
            },
            6 => match src {
                b"DELETE" => Ok(Method(Delete)),
                _ => Method::extension_inline(src),
            },
            7 => match src {
                b"OPTIONS" => Ok(Method(Options)),
                b"CONNECT" => Ok(Method(Connect)),
                _ => Method::extension_inline(src),
            },
            _ => {
                if src.len() < MAX_INLINE {
                    Method::extension_inline(src)
                } else {
                    let mut data: Vec<u8> = vec![0; src.len()];
                    write_checked(src, &mut data)?;
                    Ok(Method(ExtensionAllocated(data.into_boxed_slice())))
                }
            }
        }
    }
    fn extension_inline(src: &[u8]) -> Result<Method, InvalidMethod> {
        let mut data: [u8; MAX_INLINE] = Default::default();
        write_checked(src, &mut data)?;
        Ok(Method(ExtensionInline(data, src.len() as u8)))
    }
    
    
    
    
    
    pub fn is_safe(&self) -> bool {
        match self.0 {
            Get | Head | Options | Trace => true,
            _ => false,
        }
    }
    
    
    
    
    
    pub fn is_idempotent(&self) -> bool {
        match self.0 {
            Put | Delete => true,
            _ => self.is_safe(),
        }
    }
    
    #[inline]
    pub fn as_str(&self) -> &str {
        match self.0 {
            Options => "OPTIONS",
            Get => "GET",
            Post => "POST",
            Put => "PUT",
            Delete => "DELETE",
            Head => "HEAD",
            Trace => "TRACE",
            Connect => "CONNECT",
            Patch => "PATCH",
            ExtensionInline(ref data, len) => unsafe {
                str::from_utf8_unchecked(&data[..len as usize])
            },
            ExtensionAllocated(ref data) => unsafe { str::from_utf8_unchecked(data) },
        }
    }
}
fn write_checked(src: &[u8], dst: &mut [u8]) -> Result<(), InvalidMethod> {
    for (i, &b) in src.iter().enumerate() {
        let b = METHOD_CHARS[b as usize];
        if b == 0 {
            return Err(InvalidMethod::new());
        }
        dst[i] = b;
    }
    Ok(())
}
impl AsRef<str> for Method {
    #[inline]
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}
impl<'a> PartialEq<&'a Method> for Method {
    #[inline]
    fn eq(&self, other: &&'a Method) -> bool {
        self == *other
    }
}
impl<'a> PartialEq<Method> for &'a Method {
    #[inline]
    fn eq(&self, other: &Method) -> bool {
        *self == other
    }
}
impl PartialEq<str> for Method {
    #[inline]
    fn eq(&self, other: &str) -> bool {
        self.as_ref() == other
    }
}
impl PartialEq<Method> for str {
    #[inline]
    fn eq(&self, other: &Method) -> bool {
        self == other.as_ref()
    }
}
impl<'a> PartialEq<&'a str> for Method {
    #[inline]
    fn eq(&self, other: &&'a str) -> bool {
        self.as_ref() == *other
    }
}
impl<'a> PartialEq<Method> for &'a str {
    #[inline]
    fn eq(&self, other: &Method) -> bool {
        *self == other.as_ref()
    }
}
impl fmt::Debug for Method {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_ref())
    }
}
impl fmt::Display for Method {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt.write_str(self.as_ref())
    }
}
impl Default for Method {
    #[inline]
    fn default() -> Method {
        Method::GET
    }
}
impl<'a> From<&'a Method> for Method {
    #[inline]
    fn from(t: &'a Method) -> Self {
        t.clone()
    }
}
impl<'a> TryFrom<&'a [u8]> for Method {
    type Error = InvalidMethod;
    #[inline]
    fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
        Method::from_bytes(t)
    }
}
impl<'a> TryFrom<&'a str> for Method {
    type Error = InvalidMethod;
    #[inline]
    fn try_from(t: &'a str) -> Result<Self, Self::Error> {
        TryFrom::try_from(t.as_bytes())
    }
}
impl FromStr for Method {
    type Err = InvalidMethod;
    #[inline]
    fn from_str(t: &str) -> Result<Self, Self::Err> {
        TryFrom::try_from(t)
    }
}
impl InvalidMethod {
    fn new() -> InvalidMethod {
        InvalidMethod { _priv: () }
    }
}
impl fmt::Debug for InvalidMethod {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("InvalidMethod")
            
            .finish()
    }
}
impl fmt::Display for InvalidMethod {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}
impl Error for InvalidMethod {
    fn description(&self) -> &str {
        "invalid HTTP method"
    }
}
#[test]
fn test_method_eq() {
    assert_eq!(Method::GET, Method::GET);
    assert_eq!(Method::GET, "GET");
    assert_eq!(&Method::GET, "GET");
    assert_eq!("GET", Method::GET);
    assert_eq!("GET", &Method::GET);
    assert_eq!(&Method::GET, Method::GET);
    assert_eq!(Method::GET, &Method::GET);
}
#[test]
fn test_invalid_method() {
    assert!(Method::from_str("").is_err());
    assert!(Method::from_bytes(b"").is_err());
}
#[test]
fn test_is_idempotent() {
    assert!(Method::OPTIONS.is_idempotent());
    assert!(Method::GET.is_idempotent());
    assert!(Method::PUT.is_idempotent());
    assert!(Method::DELETE.is_idempotent());
    assert!(Method::HEAD.is_idempotent());
    assert!(Method::TRACE.is_idempotent());
    assert!(!Method::POST.is_idempotent());
    assert!(!Method::CONNECT.is_idempotent());
    assert!(!Method::PATCH.is_idempotent());
}