Documentation
// License: see LICENSE file at root directory of `master` branch

//! # Method

use {
    alloc::string::String,
    core::{
        convert::TryFrom,
        fmt::{self, Display, Formatter},
        str::FromStr,
    },
    crate::Error,
};

const METHOD_GET: &str = "GET";
const METHOD_HEAD: &str = "HEAD";
const METHOD_POST: &str = "POST";
const METHOD_PUT: &str = "PUT";
const METHOD_DELETE: &str = "DELETE";
const METHOD_CONNECT: &str = "CONNECT";
const METHOD_OPTIONS: &str = "OPTIONS";
const METHOD_TRACE: &str = "TRACE";
const METHOD_PATCH: &str = "PATCH";

/// # Method
///
/// ## References
///
/// - <https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods>
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub enum Method {

    /// # Get
    Get,

    /// # Head
    Head,

    /// # Post
    Post,

    /// # Put
    Put,

    /// # Delete
    Delete,

    /// # Connect
    Connect,

    /// # Options
    Options,

    /// # Trace
    Trace,

    /// # Patch
    Patch,

}

impl Display for Method {

    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        f.write_str(match self {
            Method::Get => METHOD_GET,
            Method::Head => METHOD_HEAD,
            Method::Post => METHOD_POST,
            Method::Put => METHOD_PUT,
            Method::Delete => METHOD_DELETE,
            Method::Connect => METHOD_CONNECT,
            Method::Options => METHOD_OPTIONS,
            Method::Trace => METHOD_TRACE,
            Method::Patch => METHOD_PATCH,
        })
    }

}

impl FromStr for Method {

    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            METHOD_GET => Ok(Method::Get),
            METHOD_HEAD => Ok(Method::Head),
            METHOD_POST => Ok(Method::Post),
            METHOD_PUT => Ok(Method::Put),
            METHOD_DELETE => Ok(Method::Delete),
            METHOD_CONNECT => Ok(Method::Connect),
            METHOD_OPTIONS => Ok(Method::Options),
            METHOD_TRACE => Ok(Method::Trace),
            METHOD_PATCH => Ok(Method::Patch),
            _ => Err(e!("Unknown method: {}", s)),
        }
    }

}

impl TryFrom<&[u8]> for Method {

    type Error = Error;

    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
        if METHOD_GET.as_bytes() == bytes {
            return Ok(Method::Get);
        }
        if METHOD_HEAD.as_bytes() == bytes {
            return Ok(Method::Head);
        }
        if METHOD_POST.as_bytes() == bytes {
            return Ok(Method::Post);
        }
        if METHOD_PUT.as_bytes() == bytes {
            return Ok(Method::Put);
        }
        if METHOD_DELETE.as_bytes() == bytes {
            return Ok(Method::Delete);
        }
        if METHOD_CONNECT.as_bytes() == bytes {
            return Ok(Method::Connect);
        }
        if METHOD_OPTIONS.as_bytes() == bytes {
            return Ok(Method::Options);
        }
        if METHOD_TRACE.as_bytes() == bytes {
            return Ok(Method::Trace);
        }
        if METHOD_PATCH.as_bytes() == bytes {
            return Ok(Method::Patch);
        }

        Err(e!("Unknown method: {:?}...", String::from_utf8_lossy(&bytes[..bytes.len().min(20)])))
    }

}