tower_grpc/metadata/key.rs
1use bytes::Bytes;
2use http::header::HeaderName;
3use std::borrow::Borrow;
4use std::error::Error;
5use std::fmt;
6use std::marker::PhantomData;
7use std::str::FromStr;
8
9use super::encoding::{Ascii, Binary, ValueEncoding};
10
11/// Represents a custom metadata field name.
12///
13/// `MetadataKey` is used as the [`MetadataMap`] key.
14///
15/// [`HeaderMap`]: struct.HeaderMap.html
16#[derive(Clone, Eq, PartialEq, Hash)]
17#[repr(transparent)]
18pub struct MetadataKey<VE: ValueEncoding> {
19 // Note: There are unsafe transmutes that assume that the memory layout
20 // of MetadataValue is identical to HeaderName
21 pub(crate) inner: http::header::HeaderName,
22 phantom: PhantomData<VE>,
23}
24
25/// A possible error when converting a `MetadataKey` from another type.
26#[derive(Debug)]
27pub struct InvalidMetadataKey {
28 _priv: (),
29}
30
31pub type AsciiMetadataKey = MetadataKey<Ascii>;
32pub type BinaryMetadataKey = MetadataKey<Binary>;
33
34impl<VE: ValueEncoding> MetadataKey<VE> {
35 /// Converts a slice of bytes to a `MetadataKey`.
36 ///
37 /// This function normalizes the input.
38 pub fn from_bytes(src: &[u8]) -> Result<Self, InvalidMetadataKey> {
39 match HeaderName::from_bytes(src) {
40 Ok(name) => {
41 if !VE::is_valid_key(name.as_str()) {
42 panic!("invalid metadata key")
43 }
44
45 Ok(MetadataKey {
46 inner: name,
47 phantom: PhantomData,
48 })
49 }
50 Err(_) => Err(InvalidMetadataKey::new()),
51 }
52 }
53
54 /// Converts a static string to a `MetadataKey`.
55 ///
56 /// This function panics when the static string is a invalid metadata key.
57 ///
58 /// This function requires the static string to only contain lowercase
59 /// characters, numerals and symbols, as per the HTTP/2.0 specification
60 /// and header names internal representation within this library.
61 ///
62 ///
63 /// # Examples
64 ///
65 /// ```
66 /// # use tower_grpc::metadata::*;
67 /// // Parsing a metadata key
68 /// let CUSTOM_KEY: &'static str = "custom-key";
69 ///
70 /// let a = AsciiMetadataKey::from_bytes(b"custom-key").unwrap();
71 /// let b = AsciiMetadataKey::from_static(CUSTOM_KEY);
72 /// assert_eq!(a, b);
73 /// ```
74 ///
75 /// ```should_panic
76 /// # use tower_grpc::metadata::*;
77 /// // Parsing a metadata key that contains invalid symbols(s):
78 /// AsciiMetadataKey::from_static("content{}{}length"); // This line panics!
79 /// ```
80 ///
81 /// ```should_panic
82 /// # use tower_grpc::metadata::*;
83 /// // Parsing a metadata key that contains invalid uppercase characters.
84 /// let a = AsciiMetadataKey::from_static("foobar");
85 /// let b = AsciiMetadataKey::from_static("FOOBAR"); // This line panics!
86 /// ```
87 ///
88 /// ```should_panic
89 /// # use tower_grpc::metadata::*;
90 /// // Parsing a -bin metadata key as an Ascii key.
91 /// let b = AsciiMetadataKey::from_static("hello-bin"); // This line panics!
92 /// ```
93 ///
94 /// ```should_panic
95 /// # use tower_grpc::metadata::*;
96 /// // Parsing a non-bin metadata key as an Binary key.
97 /// let b = BinaryMetadataKey::from_static("hello"); // This line panics!
98 /// ```
99 pub fn from_static(src: &'static str) -> Self {
100 let name = HeaderName::from_static(src);
101 if !VE::is_valid_key(name.as_str()) {
102 panic!("invalid metadata key")
103 }
104
105 MetadataKey {
106 inner: name,
107 phantom: PhantomData,
108 }
109 }
110
111 /// Returns a `str` representation of the metadata key.
112 ///
113 /// The returned string will always be lower case.
114 #[inline]
115 pub fn as_str(&self) -> &str {
116 self.inner.as_str()
117 }
118
119 /// Converts a HeaderName reference to a MetadataKey. This method assumes
120 /// that the caller has made sure that the header name has the correct
121 /// "-bin" or non-"-bin" suffix, it does not validate its input.
122 #[inline]
123 pub(crate) fn unchecked_from_header_name_ref(header_name: &HeaderName) -> &Self {
124 unsafe { &*(header_name as *const HeaderName as *const Self) }
125 }
126
127 /// Converts a HeaderName reference to a MetadataKey. This method assumes
128 /// that the caller has made sure that the header name has the correct
129 /// "-bin" or non-"-bin" suffix, it does not validate its input.
130 #[inline]
131 pub(crate) fn unchecked_from_header_name(name: HeaderName) -> Self {
132 MetadataKey {
133 inner: name,
134 phantom: PhantomData,
135 }
136 }
137}
138
139impl<VE: ValueEncoding> FromStr for MetadataKey<VE> {
140 type Err = InvalidMetadataKey;
141
142 fn from_str(s: &str) -> Result<Self, InvalidMetadataKey> {
143 MetadataKey::from_bytes(s.as_bytes()).map_err(|_| InvalidMetadataKey::new())
144 }
145}
146
147impl<VE: ValueEncoding> AsRef<str> for MetadataKey<VE> {
148 fn as_ref(&self) -> &str {
149 self.as_str()
150 }
151}
152
153impl<VE: ValueEncoding> AsRef<[u8]> for MetadataKey<VE> {
154 fn as_ref(&self) -> &[u8] {
155 self.as_str().as_bytes()
156 }
157}
158
159impl<VE: ValueEncoding> Borrow<str> for MetadataKey<VE> {
160 fn borrow(&self) -> &str {
161 self.as_str()
162 }
163}
164
165impl<VE: ValueEncoding> fmt::Debug for MetadataKey<VE> {
166 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
167 fmt::Debug::fmt(self.as_str(), fmt)
168 }
169}
170
171impl<VE: ValueEncoding> fmt::Display for MetadataKey<VE> {
172 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
173 fmt::Display::fmt(self.as_str(), fmt)
174 }
175}
176
177impl InvalidMetadataKey {
178 pub fn new() -> InvalidMetadataKey {
179 InvalidMetadataKey { _priv: () }
180 }
181}
182
183impl<'a, VE: ValueEncoding> From<&'a MetadataKey<VE>> for MetadataKey<VE> {
184 fn from(src: &'a MetadataKey<VE>) -> MetadataKey<VE> {
185 src.clone()
186 }
187}
188
189impl<VE: ValueEncoding> From<MetadataKey<VE>> for Bytes {
190 #[inline]
191 fn from(name: MetadataKey<VE>) -> Bytes {
192 name.inner.into()
193 }
194}
195
196impl<'a, VE: ValueEncoding> PartialEq<&'a MetadataKey<VE>> for MetadataKey<VE> {
197 #[inline]
198 fn eq(&self, other: &&'a MetadataKey<VE>) -> bool {
199 *self == **other
200 }
201}
202
203impl<'a, VE: ValueEncoding> PartialEq<MetadataKey<VE>> for &'a MetadataKey<VE> {
204 #[inline]
205 fn eq(&self, other: &MetadataKey<VE>) -> bool {
206 *other == *self
207 }
208}
209
210impl<VE: ValueEncoding> PartialEq<str> for MetadataKey<VE> {
211 /// Performs a case-insensitive comparison of the string against the header
212 /// name
213 ///
214 /// # Examples
215 ///
216 /// ```
217 /// # use tower_grpc::metadata::*;
218 /// let content_length = AsciiMetadataKey::from_static("content-length");
219 ///
220 /// assert_eq!(content_length, "content-length");
221 /// assert_eq!(content_length, "Content-Length");
222 /// assert_ne!(content_length, "content length");
223 /// ```
224 #[inline]
225 fn eq(&self, other: &str) -> bool {
226 self.inner.eq(other)
227 }
228}
229
230impl<VE: ValueEncoding> PartialEq<MetadataKey<VE>> for str {
231 /// Performs a case-insensitive comparison of the string against the header
232 /// name
233 ///
234 /// # Examples
235 ///
236 /// ```
237 /// # use tower_grpc::metadata::*;
238 /// let content_length = AsciiMetadataKey::from_static("content-length");
239 ///
240 /// assert_eq!(content_length, "content-length");
241 /// assert_eq!(content_length, "Content-Length");
242 /// assert_ne!(content_length, "content length");
243 /// ```
244 #[inline]
245 fn eq(&self, other: &MetadataKey<VE>) -> bool {
246 (*other).inner == *self
247 }
248}
249
250impl<'a, VE: ValueEncoding> PartialEq<&'a str> for MetadataKey<VE> {
251 /// Performs a case-insensitive comparison of the string against the header
252 /// name
253 #[inline]
254 fn eq(&self, other: &&'a str) -> bool {
255 *self == **other
256 }
257}
258
259impl<'a, VE: ValueEncoding> PartialEq<MetadataKey<VE>> for &'a str {
260 /// Performs a case-insensitive comparison of the string against the header
261 /// name
262 #[inline]
263 fn eq(&self, other: &MetadataKey<VE>) -> bool {
264 *other == *self
265 }
266}
267
268impl fmt::Display for InvalidMetadataKey {
269 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270 self.description().fmt(f)
271 }
272}
273
274impl Error for InvalidMetadataKey {
275 fn description(&self) -> &str {
276 "invalid gRPC metadata key name"
277 }
278}