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}