aex 0.1.6

A web server for rust.
Documentation
use ahash::AHashMap;
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;
use std::ops::Deref;

macro_rules! define_header_keys {
    ($($name:ident => $string:expr),* $(,)?) => {
        #[derive(Debug, Clone)]
        pub enum HeaderKey {
            $($name,)*
            Custom(String),
        }

        impl HeaderKey {
            #[inline]
            pub fn as_str(&self) -> &str {
                match self {
                    $(
                        HeaderKey::$name => $string,
                    )*
                    HeaderKey::Custom(s) => s.as_str(),
                }
            }

            #[inline]
            pub fn from_str(s: &str) -> Option<Self> {
                let s_trimmed = s.trim();
                let s_lower = s_trimmed.to_ascii_lowercase();
                match s_lower.as_str() {
                    $(
                        s if s == $string.to_ascii_lowercase() => Some(HeaderKey::$name),
                    )*
                    _ => Some(HeaderKey::Custom(s_trimmed.to_string())),
                }
            }
        }

        // --- 手动实现比较逻辑 ---

        impl PartialEq for HeaderKey {
            fn eq(&self, other: &Self) -> bool {
                self.as_str().to_ascii_lowercase() == other.as_str().to_ascii_lowercase()
            }
        }

        impl Eq for HeaderKey {}

        impl Hash for HeaderKey {
            fn hash<H: Hasher>(&self, state: &mut H) {
                self.as_str().to_ascii_lowercase().hash(state);
            }
        }
    };
}
// 使用宏统一管理所有 70+ 个标准 Header
define_header_keys! {
    // ===== General Headers =====
    CacheControl => "Cache-Control",
    Connection => "Connection",
    Date => "Date",
    Pragma => "Pragma",
    Trailer => "Trailer",
    TransferEncoding => "Transfer-Encoding",
    Upgrade => "Upgrade",
    Via => "Via",
    Warning => "Warning",

    // ===== Request Headers =====
    Accept => "Accept",
    AcceptCharset => "Accept-Charset",
    AcceptEncoding => "Accept-Encoding",
    AcceptLanguage => "Accept-Language",
    Authorization => "Authorization",
    Cookie => "Cookie",
    Expect => "Expect",
    From => "From",
    Host => "Host",
    IfMatch => "If-Match",
    IfModifiedSince => "If-Modified-Since",
    IfNoneMatch => "If-None-Match",
    IfRange => "If-Range",
    IfUnmodifiedSince => "If-Unmodified-Since",
    MaxForwards => "Max-Forwards",
    Origin => "Origin",
    Range => "Range",
    Referer => "Referer",
    TE => "TE",
    UserAgent => "User-Agent",

    // ===== Response Headers =====
    AcceptRanges => "Accept-Ranges",
    Age => "Age",
    ETag => "ETag",
    Location => "Location",
    ProxyAuthenticate => "Proxy-Authenticate",
    RetryAfter => "Retry-After",
    Server => "Server",
    SetCookie => "Set-Cookie",
    Vary => "Vary",
    WWWAuthenticate => "WWW-Authenticate",

    // ===== Entity Headers =====
    Allow => "Allow",
    ContentEncoding => "Content-Encoding",
    ContentLanguage => "Content-Language",
    ContentLength => "Content-Length",
    ContentLocation => "Content-Location",
    ContentRange => "Content-Range",
    ContentType => "Content-Type",
    Expires => "Expires",
    LastModified => "Last-Modified",

    // ===== CORS / Fetch =====
    AccessControlAllowCredentials => "Access-Control-Allow-Credentials",
    AccessControlAllowHeaders => "Access-Control-Allow-Headers",
    AccessControlAllowMethods => "Access-Control-Allow-Methods",
    AccessControlAllowOrigin => "Access-Control-Allow-Origin",
    AccessControlExposeHeaders => "Access-Control-Expose-Headers",
    AccessControlMaxAge => "Access-Control-Max-Age",

    SecFetchDest => "Sec-Fetch-Dest",
    SecFetchMode => "Sec-Fetch-Mode",
    SecFetchSite => "Sec-Fetch-Site",
    SecFetchUser => "Sec-Fetch-User",

    // ===== WebSocket =====
    SecWebSocketAccept => "Sec-WebSocket-Accept",
    SecWebSocketExtensions => "Sec-WebSocket-Extensions",
    SecWebSocketKey => "Sec-WebSocket-Key",
    SecWebSocketProtocol => "Sec-WebSocket-Protocol",
    SecWebSocketVersion => "Sec-WebSocket-Version",

    // ===== Proxy =====
    Forwarded => "Forwarded",
    XForwardedFor => "X-Forwarded-For",
    XForwardedHost => "X-Forwarded-Host",
    XForwardedProto => "X-Forwarded-Proto",

    // ===== Misc =====
    DNT => "DNT",
    KeepAlive => "Keep-Alive",
    UpgradeInsecureRequests => "Upgrade-Insecure-Requests",
}

impl From<&str> for HeaderKey {
    fn from(s: &str) -> Self {
        Self::from_str(s).unwrap_or(HeaderKey::Custom(s.to_string()))
    }
}

impl From<String> for HeaderKey {
    fn from(s: String) -> Self {
        Self::from_str(&s).unwrap_or(HeaderKey::Custom(s))
    }
}

impl fmt::Display for HeaderKey {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

#[derive(Debug, Clone)]
pub struct Headers(AHashMap<HeaderKey, String>);

impl Headers {
    pub fn new() -> Self {
        Self(AHashMap::with_capacity(16))
    }

    /// 链式调用:插入 Header 并返回自身所有权
    pub fn with(mut self, key: HeaderKey, value: impl Into<String>) -> Self {
        self.0.insert(key, value.into());
        self
    }

    /// 就地修改:插入 Header 并返回旧值(如果有)
    pub fn insert(&mut self, key: HeaderKey, value: impl Into<String>) -> Option<String> {
        self.0.insert(key, value.into())
    }

    /// 获取 Header 引用
    pub fn get(&self, key: &HeaderKey) -> Option<&String> {
        self.0.get(key)
    }

    /// 移除 Header
    pub fn remove(&mut self, key: &HeaderKey) -> Option<String> {
        self.0.remove(key)
    }

    /// 检查是否存在
    pub fn contains(&self, key: &HeaderKey) -> bool {
        self.0.contains_key(key)
    }
}

// 技巧:实现 Deref 使得 Headers 可以像 HashMap 一样被迭代或读取
impl Deref for Headers {
    type Target = AHashMap<HeaderKey, String>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl From<AHashMap<HeaderKey, String>> for Headers {
    fn from(map: AHashMap<HeaderKey, String>) -> Self {
        Self(map)
    }
}

impl From<Headers> for AHashMap<HeaderKey, String> {
    fn from(headers: Headers) -> Self {
        headers.0
    }
}

impl FromIterator<(HeaderKey, String)> for Headers {
    fn from_iter<I: IntoIterator<Item = (HeaderKey, String)>>(iter: I) -> Self {
        Self(AHashMap::from_iter(iter))
    }
}

impl<'a> IntoIterator for &'a Headers {
    type Item = (&'a HeaderKey, &'a String);
    type IntoIter = <&'a AHashMap<HeaderKey, String> as IntoIterator>::IntoIter;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl IntoIterator for Headers {
    type Item = (HeaderKey, String);
    type IntoIter = <AHashMap<HeaderKey, String> as IntoIterator>::IntoIter;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}