Skip to main content

trillium_http/headers/
header_name.rs

1use super::{KnownHeaderName, UnknownHeaderName};
2use crate::Error;
3use HeaderNameInner::{KnownHeader, UnknownHeader};
4use std::{
5    fmt::{self, Debug, Display, Formatter},
6    hash::Hash,
7    str::FromStr,
8};
9
10/// The name of a http header. This can be either a
11/// [`KnownHeaderName`] or a string representation of an unknown
12/// header.
13#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
14pub struct HeaderName<'a>(pub(super) HeaderNameInner<'a>);
15
16impl Debug for HeaderName<'_> {
17    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
18        Debug::fmt(&self.0, f)
19    }
20}
21
22#[cfg(feature = "parse")]
23impl<'a> HeaderName<'a> {
24    pub(crate) fn parse(bytes: &'a [u8]) -> Result<Self, Error> {
25        std::str::from_utf8(bytes)
26            .map_err(|_| Error::InvalidHeaderName)
27            .map(HeaderName::from)
28    }
29}
30
31#[cfg(feature = "serde")]
32impl serde::Serialize for HeaderName<'_> {
33    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
34    where
35        S: serde::Serializer,
36    {
37        serializer.serialize_str(self.as_ref())
38    }
39}
40
41#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
42pub(super) enum HeaderNameInner<'a> {
43    /// A `KnownHeaderName`
44    KnownHeader(KnownHeaderName),
45    UnknownHeader(UnknownHeaderName<'a>),
46}
47
48impl Debug for HeaderNameInner<'_> {
49    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
50        match self {
51            Self::KnownHeader(known) => Debug::fmt(known, f),
52            Self::UnknownHeader(unknown) => Debug::fmt(unknown, f),
53        }
54    }
55}
56
57impl<'a> HeaderName<'a> {
58    /// Convert a potentially-borrowed headername to a static
59    /// headername _by value_.
60    #[must_use]
61    pub fn into_owned(self) -> HeaderName<'static> {
62        HeaderName(match self.0 {
63            KnownHeader(known) => KnownHeader(known),
64            UnknownHeader(uhn) => UnknownHeader(uhn.into_owned()),
65        })
66    }
67
68    // /// Convert a header name into a lowercase variant suitable for use in http/2-3
69    // #[must_use]
70    // pub fn into_lower(self) -> HeaderName<'a> {
71    //     HeaderName(match self.0 {
72    //         KnownHeader(known) => KnownHeader(known),
73    //         UnknownHeader(uhn) => UnknownHeader(uhn.into_lower()),
74    //     })
75    // }
76
77    /// Turn a `&'b HeaderName<'a>` into a `HeaderName<'b>`
78    pub fn reborrow<'b: 'a>(&'b self) -> HeaderName<'b> {
79        match self.0 {
80            KnownHeader(khn) => khn.into(),
81            UnknownHeader(ref uhn) => uhn.reborrow().into(),
82        }
83    }
84
85    /// Convert a potentially-borrowed headername to a static
86    /// headername _by cloning if needed from a borrow_. If you have
87    /// ownership of a headername with a non-static lifetime, it is
88    /// preferable to use `into_owned`. This is the equivalent of
89    /// `self.clone().into_owned()`.
90    #[must_use]
91    pub fn to_owned(&self) -> HeaderName<'static> {
92        self.clone().into_owned()
93    }
94
95    /// Determine if this header name contains only the appropriate characters
96    ///
97    /// since 0.3.12
98    pub fn is_valid(&self) -> bool {
99        match &self.0 {
100            KnownHeader(_) => true,
101            UnknownHeader(uh) => uh.is_valid(),
102        }
103    }
104}
105
106impl PartialEq<KnownHeaderName> for HeaderName<'_> {
107    fn eq(&self, other: &KnownHeaderName) -> bool {
108        match &self.0 {
109            KnownHeader(k) => other == k,
110            UnknownHeader(_) => false,
111        }
112    }
113}
114
115impl PartialEq<KnownHeaderName> for &HeaderName<'_> {
116    fn eq(&self, other: &KnownHeaderName) -> bool {
117        match &self.0 {
118            KnownHeader(k) => other == k,
119            UnknownHeader(_) => false,
120        }
121    }
122}
123
124impl PartialEq<str> for HeaderName<'_> {
125    fn eq(&self, other: &str) -> bool {
126        self.as_ref() == other
127    }
128}
129
130impl PartialEq<&str> for HeaderName<'_> {
131    fn eq(&self, other: &&str) -> bool {
132        self.as_ref() == *other
133    }
134}
135
136impl From<String> for HeaderName<'static> {
137    fn from(s: String) -> Self {
138        Self(match s.parse::<KnownHeaderName>() {
139            Ok(khn) => KnownHeader(khn),
140            Err(()) => UnknownHeader(UnknownHeaderName::from(s)),
141        })
142    }
143}
144
145impl<'a> From<&'a str> for HeaderName<'a> {
146    fn from(s: &'a str) -> Self {
147        Self(match s.parse::<KnownHeaderName>() {
148            Ok(khn) => KnownHeader(khn),
149            Err(_e) => UnknownHeader(UnknownHeaderName::from(s)),
150        })
151    }
152}
153
154impl<'a> From<&'a HeaderName<'_>> for HeaderName<'a> {
155    fn from(value: &'a HeaderName<'_>) -> Self {
156        value.reborrow()
157    }
158}
159
160impl FromStr for HeaderName<'static> {
161    type Err = Error;
162
163    fn from_str(s: &str) -> Result<Self, Self::Err> {
164        if let Ok(known) = s.parse::<KnownHeaderName>() {
165            return Ok(known.into());
166        }
167        let uhn = UnknownHeaderName::from(s.to_string());
168        if uhn.is_valid() {
169            Ok(uhn.into())
170        } else {
171            Err(Error::InvalidHeaderName)
172        }
173    }
174}
175
176impl AsRef<str> for HeaderName<'_> {
177    fn as_ref(&self) -> &str {
178        match &self.0 {
179            KnownHeader(khn) => khn.as_ref(),
180            UnknownHeader(u) => u.as_ref(),
181        }
182    }
183}
184
185impl Display for HeaderName<'_> {
186    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
187        f.write_str(self.as_ref())
188    }
189}