trillium_http/headers/
header_name.rs

1use std::{
2    fmt::{self, Debug, Display, Formatter},
3    hash::Hash,
4    str::FromStr,
5};
6
7use super::{KnownHeaderName, UnknownHeaderName};
8use crate::Error;
9use HeaderNameInner::{KnownHeader, UnknownHeader};
10
11/// The name of a http header. This can be either a
12/// [`KnownHeaderName`] or a string representation of an unknown
13/// header.
14#[derive(Clone, Debug, PartialEq, Eq, Hash)]
15pub struct HeaderName<'a>(pub(super) HeaderNameInner<'a>);
16
17#[cfg(feature = "serde")]
18impl serde::Serialize for HeaderName<'_> {
19    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
20    where
21        S: serde::Serializer,
22    {
23        serializer.serialize_str(self.as_ref())
24    }
25}
26
27#[derive(Clone, Debug, PartialEq, Eq, Hash)]
28pub(super) enum HeaderNameInner<'a> {
29    /// A `KnownHeaderName`
30    KnownHeader(KnownHeaderName),
31    UnknownHeader(UnknownHeaderName<'a>),
32}
33
34impl<'a> HeaderName<'a> {
35    /// Convert a potentially-borrowed headername to a static
36    /// headername _by value_.
37    #[must_use]
38    pub fn into_owned(self) -> HeaderName<'static> {
39        HeaderName(match self.0 {
40            KnownHeader(known) => KnownHeader(known),
41            UnknownHeader(uhn) => UnknownHeader(uhn.into_owned()),
42        })
43    }
44
45    /// Convert a potentially-borrowed headername to a static
46    /// headername _by cloning if needed from a borrow_. If you have
47    /// ownership of a headername with a non-static lifetime, it is
48    /// preferable to use `into_owned`. This is the equivalent of
49    /// `self.clone().into_owned()`.
50    #[must_use]
51    pub fn to_owned(&self) -> HeaderName<'static> {
52        self.clone().into_owned()
53    }
54
55    /// Determine if this header name contains only the appropriate characters
56    ///
57    /// since 0.3.12
58    pub fn is_valid(&self) -> bool {
59        match &self.0 {
60            KnownHeader(_) => true,
61            UnknownHeader(uh) => uh.is_valid(),
62        }
63    }
64}
65
66impl PartialEq<KnownHeaderName> for HeaderName<'_> {
67    fn eq(&self, other: &KnownHeaderName) -> bool {
68        match &self.0 {
69            KnownHeader(k) => other == k,
70            UnknownHeader(_) => false,
71        }
72    }
73}
74
75impl PartialEq<KnownHeaderName> for &HeaderName<'_> {
76    fn eq(&self, other: &KnownHeaderName) -> bool {
77        match &self.0 {
78            KnownHeader(k) => other == k,
79            UnknownHeader(_) => false,
80        }
81    }
82}
83
84impl From<String> for HeaderName<'static> {
85    fn from(s: String) -> Self {
86        Self(match s.parse::<KnownHeaderName>() {
87            Ok(khn) => KnownHeader(khn),
88            Err(()) => UnknownHeader(UnknownHeaderName::from(s)),
89        })
90    }
91}
92
93impl<'a> From<&'a str> for HeaderName<'a> {
94    fn from(s: &'a str) -> Self {
95        Self(match s.parse::<KnownHeaderName>() {
96            Ok(khn) => KnownHeader(khn),
97            Err(_e) => UnknownHeader(UnknownHeaderName::from(s)),
98        })
99    }
100}
101
102impl FromStr for HeaderName<'static> {
103    type Err = Error;
104
105    fn from_str(s: &str) -> Result<Self, Self::Err> {
106        if let Ok(known) = s.parse::<KnownHeaderName>() {
107            return Ok(known.into());
108        }
109        let uhn = UnknownHeaderName::from(s.to_string());
110        if uhn.is_valid() {
111            Ok(uhn.into())
112        } else {
113            Err(Error::MalformedHeader(s.to_string().into()))
114        }
115    }
116}
117
118impl AsRef<str> for HeaderName<'_> {
119    fn as_ref(&self) -> &str {
120        match &self.0 {
121            KnownHeader(khn) => khn.as_ref(),
122            UnknownHeader(u) => u.as_ref(),
123        }
124    }
125}
126
127impl Display for HeaderName<'_> {
128    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
129        f.write_str(self.as_ref())
130    }
131}