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 {}