1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use std::{
    fmt,
    hash::{Hash, Hasher},
};

/// A valid HTTP method
#[derive(Debug, Clone, Copy)]
pub enum Method {
    Get,
    Post,
    Put,
    Delete,
    Patch,
}

impl Method {
    pub const fn name(self) -> &'static str {
        match self {
            Method::Get => "GET",
            Method::Post => "POST",
            Method::Put => "PUT",
            Method::Delete => "DELETE",
            Method::Patch => "PATCH",
        }
    }
}

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

/// A case-sensitive header name, with case-insensitive
/// `Eq` & `Hash` implementations.
#[derive(Clone, Copy, Eq)]
pub(crate) struct HeaderName<'a>(pub &'a str);

impl fmt::Debug for HeaderName<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Display for HeaderName<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

/// Case-insensitive hash.
impl Hash for HeaderName<'_> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        for c in self.0.bytes() {
            c.to_ascii_lowercase().hash(state);
        }
    }
}

/// Case-insensitive equals.
impl PartialEq for HeaderName<'_> {
    fn eq(&self, other: &Self) -> bool {
        self.0.eq_ignore_ascii_case(other.0)
    }
}

#[test]
fn case_insensitive_eq() {
    let a = HeaderName("X-Custom");
    let b = HeaderName("x-custom");
    assert_eq!(a, b);
}

#[test]
fn case_insensitive_hash() {
    let a = HeaderName("X-Custom");
    let b = HeaderName("x-custom");

    let hash = |thing: HeaderName<'_>| {
        let mut s = std::collections::hash_map::DefaultHasher::new();
        thing.hash(&mut s);
        s.finish()
    };

    assert_eq!(hash(a), hash(b));
}