volo_grpc/metadata/
key.rs

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