Skip to main content

volo_grpc/metadata/
value.rs

1//! These codes are copied from `tonic/src/metadata/value.rs` and may be modified by us.
2
3use std::{
4    cmp,
5    error::Error,
6    fmt,
7    hash::{Hash, Hasher},
8    marker::PhantomData,
9    str::FromStr,
10};
11
12use bytes::Bytes;
13use http::header::HeaderValue;
14
15use super::{
16    encoding::{Ascii, Binary, InvalidMetadataValue, InvalidMetadataValueBytes, ValueEncoding},
17    key::MetadataKey,
18};
19
20/// Represents a custom metadata field value.
21///
22/// `MetadataValue` is used as the [`MetadataMap`] value.
23///
24/// [`HeaderMap`]: struct.HeaderMap.html
25/// [`MetadataMap`]: struct.MetadataMap.html
26#[derive(Clone)]
27#[repr(transparent)]
28pub struct MetadataValue<VE: ValueEncoding> {
29    // Note: There are unsafe transmutes that assume that the memory layout
30    // of MetadataValue is identical to HeaderValue
31    pub(crate) inner: HeaderValue,
32    phantom: PhantomData<VE>,
33}
34
35/// A possible error when converting a `MetadataValue` to a string representation.
36///
37/// Metadata field values may contain opaque bytes, in which case it is not
38/// possible to represent the value as a string.
39#[derive(Debug)]
40pub struct ToStrError {
41    _priv: (),
42}
43
44/// An ascii metadata value.
45pub type AsciiMetadataValue = MetadataValue<Ascii>;
46/// A binary metadata value.
47pub type BinaryMetadataValue = MetadataValue<Binary>;
48
49impl<VE: ValueEncoding> MetadataValue<VE> {
50    /// Convert a static string to a `MetadataValue`.
51    ///
52    /// This function will not perform any copying, however the string is
53    /// checked to ensure that no invalid characters are present.
54    ///
55    /// For Ascii values, only visible ASCII characters (32-127) are permitted.
56    /// For Binary values, the string must be valid base64.
57    ///
58    /// # Panics
59    ///
60    /// This function panics if the argument contains invalid metadata value
61    /// characters.
62    ///
63    /// # Examples
64    ///
65    /// ```
66    /// # use volo_grpc::metadata::*;
67    /// let val = AsciiMetadataValue::from_static("hello");
68    /// assert_eq!(val, "hello");
69    /// ```
70    ///
71    /// ```
72    /// # use volo_grpc::metadata::*;
73    /// let val = BinaryMetadataValue::from_static("SGVsbG8hIQ==");
74    /// assert_eq!(val, "Hello!!");
75    /// ```
76    #[inline]
77    pub fn from_static(src: &'static str) -> Self {
78        Self {
79            inner: VE::from_static(src),
80            phantom: PhantomData,
81        }
82    }
83
84    /// Attempt to convert a byte slice to a `MetadataValue`.
85    ///
86    /// For Ascii metadata values, If the argument contains invalid metadata
87    /// value bytes, an error is returned. Only byte values between 32 and 255
88    /// (inclusive) are permitted, excluding byte 127 (DEL).
89    ///
90    /// For Binary metadata values this method cannot fail. See also the Binary
91    /// only version of this method `from_bytes`.
92    ///
93    /// This function is intended to be replaced in the future by a `TryFrom`
94    /// implementation once the trait is stabilized in std.
95    ///
96    /// # Examples
97    ///
98    /// ```
99    /// # use volo_grpc::metadata::*;
100    /// let val = AsciiMetadataValue::try_from_bytes(b"hello\xfa").unwrap();
101    /// assert_eq!(val, &b"hello\xfa"[..]);
102    /// ```
103    ///
104    /// An invalid value
105    ///
106    /// ```
107    /// # use volo_grpc::metadata::*;
108    /// let val = AsciiMetadataValue::try_from_bytes(b"\n");
109    /// assert!(val.is_err());
110    /// ```
111    #[inline]
112    pub fn try_from_bytes(src: &[u8]) -> Result<Self, InvalidMetadataValueBytes> {
113        VE::from_bytes(src).map(|value| Self {
114            inner: value,
115            phantom: PhantomData,
116        })
117    }
118
119    /// Attempt to convert a `Bytes` buffer to a `MetadataValue`.
120    ///
121    /// For `MetadataValue<Ascii>`, if the argument contains invalid metadata
122    /// value bytes, an error is returned. Only byte values between 32 and 255
123    /// (inclusive) are permitted, excluding byte 127 (DEL).
124    ///
125    /// For `MetadataValue<Binary>`, if the argument is not valid base64, an
126    /// error is returned. In use cases where the input is not base64 encoded,
127    /// use `from_bytes`; if the value has to be encoded it's not possible to
128    /// share the memory anyways.
129    ///
130    /// This function is intended to be replaced in the future by a `TryFrom`
131    /// implementation once the trait is stabilized in std.
132    #[inline]
133    pub fn from_shared(src: Bytes) -> Result<Self, InvalidMetadataValueBytes> {
134        VE::from_shared(src).map(|value| Self {
135            inner: value,
136            phantom: PhantomData,
137        })
138    }
139
140    /// Convert a `Bytes` directly into a `MetadataValue` without validating.
141    /// For `MetadataValue<Binary>` the provided parameter must be base64
142    /// encoded without padding bytes at the end.
143    ///
144    /// # Safety
145    ///
146    /// will not validate src
147    #[inline]
148    pub unsafe fn from_shared_unchecked(src: Bytes) -> Self {
149        Self {
150            inner: unsafe { HeaderValue::from_maybe_shared_unchecked(src) },
151            phantom: PhantomData,
152        }
153    }
154
155    /// Returns true if the `MetadataValue` has a length of zero bytes.
156    ///
157    /// # Examples
158    ///
159    /// ```
160    /// # use volo_grpc::metadata::*;
161    /// let val = AsciiMetadataValue::from_static("");
162    /// assert!(val.is_empty());
163    ///
164    /// let val = AsciiMetadataValue::from_static("hello");
165    /// assert!(!val.is_empty());
166    /// ```
167    #[inline]
168    pub fn is_empty(&self) -> bool {
169        VE::is_empty(self.inner.as_bytes())
170    }
171
172    /// Converts a `MetadataValue` to a Bytes buffer. This method cannot
173    /// fail for Ascii values. For Ascii values, `as_bytes` is more convenient
174    /// to use.
175    ///
176    /// # Examples
177    ///
178    /// ```
179    /// # use volo_grpc::metadata::*;
180    /// let val = AsciiMetadataValue::from_static("hello");
181    /// assert_eq!(val.to_bytes().unwrap().as_ref(), b"hello");
182    /// ```
183    ///
184    /// ```
185    /// # use volo_grpc::metadata::*;
186    /// let val = BinaryMetadataValue::from_bytes(b"hello");
187    /// assert_eq!(val.to_bytes().unwrap().as_ref(), b"hello");
188    /// ```
189    #[inline]
190    pub fn to_bytes(&self) -> Result<Bytes, InvalidMetadataValueBytes> {
191        VE::decode(self.inner.as_bytes())
192    }
193
194    /// Mark that the metadata value represents sensitive information.
195    ///
196    /// # Examples
197    ///
198    /// ```
199    /// # use volo_grpc::metadata::*;
200    /// let mut val = AsciiMetadataValue::from_static("my secret");
201    ///
202    /// val.set_sensitive(true);
203    /// assert!(val.is_sensitive());
204    ///
205    /// val.set_sensitive(false);
206    /// assert!(!val.is_sensitive());
207    /// ```
208    #[inline]
209    pub fn set_sensitive(&mut self, val: bool) {
210        self.inner.set_sensitive(val);
211    }
212
213    /// Returns `true` if the value represents sensitive data.
214    ///
215    /// Sensitive data could represent passwords or other data that should not
216    /// be stored on disk or in memory. This setting can be used by components
217    /// like caches to avoid storing the value. HPACK encoders must set the
218    /// metadata field to never index when `is_sensitive` returns true.
219    ///
220    /// Note that sensitivity is not factored into equality or ordering.
221    ///
222    /// # Examples
223    ///
224    /// ```
225    /// # use volo_grpc::metadata::*;
226    /// let mut val = AsciiMetadataValue::from_static("my secret");
227    ///
228    /// val.set_sensitive(true);
229    /// assert!(val.is_sensitive());
230    ///
231    /// val.set_sensitive(false);
232    /// assert!(!val.is_sensitive());
233    /// ```
234    #[inline]
235    pub fn is_sensitive(&self) -> bool {
236        self.inner.is_sensitive()
237    }
238
239    /// Converts a `MetadataValue` to a byte slice. For Binary values, the
240    /// return value is base64 encoded.
241    ///
242    /// # Examples
243    ///
244    /// ```
245    /// # use volo_grpc::metadata::*;
246    /// let val = AsciiMetadataValue::from_static("hello");
247    /// assert_eq!(val.as_encoded_bytes(), b"hello");
248    /// ```
249    ///
250    /// ```
251    /// # use volo_grpc::metadata::*;
252    /// let val = BinaryMetadataValue::from_bytes(b"Hello!");
253    /// assert_eq!(val.as_encoded_bytes(), b"SGVsbG8h");
254    /// ```
255    #[inline]
256    pub fn as_encoded_bytes(&self) -> &[u8] {
257        self.inner.as_bytes()
258    }
259
260    /// Converts a HeaderValue to a `MetadataValue`. This method assumes that the
261    /// caller has made sure that the value is of the correct Ascii or Binary
262    /// value encoding.
263    #[inline]
264    pub(crate) fn unchecked_from_header_value(value: HeaderValue) -> Self {
265        Self {
266            inner: value,
267            phantom: PhantomData,
268        }
269    }
270
271    /// Converts a HeaderValue reference to a `MetadataValue`. This method assumes
272    /// that the caller has made sure that the value is of the correct Ascii or
273    /// Binary value encoding.
274    #[inline]
275    pub(crate) fn unchecked_from_header_value_ref(header_value: &HeaderValue) -> &Self {
276        // SAFETY: HeaderName and Self have the same Layout, so it's safe to use mem::transmute
277        unsafe { &*(header_value as *const HeaderValue as *const Self) }
278    }
279
280    /// Converts a HeaderValue reference to a `MetadataValue`. This method assumes
281    /// that the caller has made sure that the value is of the correct Ascii or
282    /// Binary value encoding.
283    #[inline]
284    pub(crate) fn unchecked_from_mut_header_value_ref(header_value: &mut HeaderValue) -> &mut Self {
285        // SAFETY: HeaderName and Self have the same Layout, so it's safe to use mem::transmute
286        unsafe { &mut *(header_value as *mut HeaderValue as *mut Self) }
287    }
288}
289
290// is_empty is defined in the generic impl block above
291#[allow(clippy::len_without_is_empty)]
292impl MetadataValue<Ascii> {
293    /// Attempt to convert a string to a `MetadataValue<Ascii>`.
294    ///
295    /// If the argument contains invalid metadata value characters, an error is
296    /// returned. Only visible ASCII characters (32-127) are permitted. Use
297    /// `from_bytes` to create a `MetadataValue` that includes opaque octets
298    /// (128-255).
299    ///
300    /// This function is intended to be replaced in the future by a `TryFrom`
301    /// implementation once the trait is stabilized in std.
302    ///
303    /// # Examples
304    ///
305    /// ```
306    /// # use volo_grpc::metadata::*;
307    /// let val = AsciiMetadataValue::from_str("hello").unwrap();
308    /// assert_eq!(val, "hello");
309    /// ```
310    ///
311    /// An invalid value
312    ///
313    /// ```
314    /// # use volo_grpc::metadata::*;
315    /// let val = AsciiMetadataValue::from_str("\n");
316    /// assert!(val.is_err());
317    /// ```
318    #[allow(clippy::should_implement_trait)]
319    #[inline]
320    pub fn from_str(src: &str) -> Result<Self, InvalidMetadataValue> {
321        HeaderValue::from_str(src)
322            .map(|value| Self {
323                inner: value,
324                phantom: PhantomData,
325            })
326            .map_err(|_| InvalidMetadataValue::new())
327    }
328
329    /// Converts a MetadataKey into a `MetadataValue<Ascii>`.
330    ///
331    /// Since every valid MetadataKey is a valid `MetadataValue` this is done
332    /// infallibly.
333    ///
334    /// # Examples
335    ///
336    /// ```
337    /// # use volo_grpc::metadata::*;
338    /// let val = AsciiMetadataValue::from_key::<Ascii>("accept".parse().unwrap());
339    /// assert_eq!(val, AsciiMetadataValue::try_from_bytes(b"accept").unwrap());
340    /// ```
341    #[inline]
342    pub fn from_key<KeyVE: ValueEncoding>(key: MetadataKey<KeyVE>) -> Self {
343        key.into()
344    }
345
346    /// Returns the length of `self`, in bytes.
347    ///
348    /// This method is not available for `MetadataValue<Binary>` because that
349    /// cannot be implemented in constant time, which most people would probably
350    /// expect. To get the length of `MetadataValue<Binary>`, convert it to a
351    /// Bytes value and measure its length.
352    ///
353    /// # Examples
354    ///
355    /// ```
356    /// # use volo_grpc::metadata::*;
357    /// let val = AsciiMetadataValue::from_static("hello");
358    /// assert_eq!(val.len(), 5);
359    /// ```
360    #[inline]
361    pub fn len(&self) -> usize {
362        self.inner.len()
363    }
364
365    /// Yields a `&str` slice if the `MetadataValue` only contains visible ASCII
366    /// chars.
367    ///
368    /// This function will perform a scan of the metadata value, checking all the
369    /// characters.
370    ///
371    /// # Examples
372    ///
373    /// ```
374    /// # use volo_grpc::metadata::*;
375    /// let val = AsciiMetadataValue::from_static("hello");
376    /// assert_eq!(val.to_str().unwrap(), "hello");
377    /// ```
378    pub fn to_str(&self) -> Result<&str, ToStrError> {
379        self.inner.to_str().map_err(|_| ToStrError::new())
380    }
381
382    /// Converts a `MetadataValue` to a byte slice. For Binary values, use
383    /// `to_bytes`.
384    ///
385    /// # Examples
386    ///
387    /// ```
388    /// # use volo_grpc::metadata::*;
389    /// let val = AsciiMetadataValue::from_static("hello");
390    /// assert_eq!(val.as_bytes(), b"hello");
391    /// ```
392    #[inline]
393    pub fn as_bytes(&self) -> &[u8] {
394        self.inner.as_bytes()
395    }
396}
397
398impl MetadataValue<Binary> {
399    /// Convert a byte slice to a `MetadataValue<Binary>`.
400    ///
401    /// # Examples
402    ///
403    /// ```
404    /// # use volo_grpc::metadata::*;
405    /// let val = BinaryMetadataValue::from_bytes(b"hello\xfa");
406    /// assert_eq!(val, &b"hello\xfa"[..]);
407    /// ```
408    #[inline]
409    pub fn from_bytes(src: &[u8]) -> Self {
410        // Only the Ascii version of try_from_bytes can fail.
411        Self::try_from_bytes(src).unwrap()
412    }
413}
414
415impl<VE: ValueEncoding> AsRef<[u8]> for MetadataValue<VE> {
416    #[inline]
417    fn as_ref(&self) -> &[u8] {
418        self.inner.as_ref()
419    }
420}
421
422impl<VE: ValueEncoding> fmt::Debug for MetadataValue<VE> {
423    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
424        VE::fmt(&self.inner, f)
425    }
426}
427
428impl<KeyVE: ValueEncoding> From<MetadataKey<KeyVE>> for MetadataValue<Ascii> {
429    #[inline]
430    fn from(h: MetadataKey<KeyVE>) -> Self {
431        Self {
432            inner: h.inner.into(),
433            phantom: PhantomData,
434        }
435    }
436}
437
438macro_rules! from_integers {
439    ($($name:ident: $t:ident => $max_len:expr),*) => {$(
440        impl From<$t> for MetadataValue<Ascii> {
441            fn from(num: $t) -> MetadataValue<Ascii> {
442                MetadataValue {
443                    inner: HeaderValue::from(num),
444                    phantom: PhantomData,
445                }
446            }
447        }
448
449        #[test]
450        fn $name() {
451            let n: $t = 55;
452            let val = AsciiMetadataValue::from(n);
453            assert_eq!(val, &n.to_string());
454
455            let n = $t::MAX;
456            let val = AsciiMetadataValue::from(n);
457            assert_eq!(val, &n.to_string());
458        }
459    )*};
460}
461
462from_integers! {
463    // integer type => maximum decimal length
464
465    // u8 purposely left off... AsciiMetadataValue::from(b'3') could be confusing
466    from_u16: u16 => 5,
467    from_i16: i16 => 6,
468    from_u32: u32 => 10,
469    from_i32: i32 => 11,
470    from_u64: u64 => 20,
471    from_i64: i64 => 20
472}
473
474#[cfg(target_pointer_width = "16")]
475from_integers! {
476    from_usize: usize => 5,
477    from_isize: isize => 6
478}
479
480#[cfg(target_pointer_width = "32")]
481from_integers! {
482    from_usize: usize => 10,
483    from_isize: isize => 11
484}
485
486#[cfg(target_pointer_width = "64")]
487from_integers! {
488    from_usize: usize => 20,
489    from_isize: isize => 20
490}
491
492#[cfg(test)]
493mod from_metadata_value_tests {
494    use super::*;
495    use crate::metadata::MetadataMap;
496
497    #[test]
498    fn it_can_insert_metadata_key_as_metadata_value() {
499        let mut map = MetadataMap::new();
500        map.insert(
501            "accept",
502            MetadataKey::<Ascii>::from_bytes(b"hello-world")
503                .unwrap()
504                .into(),
505        );
506
507        assert_eq!(
508            map.get("accept").unwrap(),
509            AsciiMetadataValue::try_from_bytes(b"hello-world").unwrap()
510        );
511    }
512}
513
514impl FromStr for MetadataValue<Ascii> {
515    type Err = InvalidMetadataValue;
516
517    #[inline]
518    fn from_str(s: &str) -> Result<Self, Self::Err> {
519        Self::from_str(s)
520    }
521}
522
523impl<VE: ValueEncoding> From<MetadataValue<VE>> for Bytes {
524    #[inline]
525    fn from(value: MetadataValue<VE>) -> Bytes {
526        Bytes::copy_from_slice(value.inner.as_bytes())
527    }
528}
529
530impl<'a, VE: ValueEncoding> From<&'a MetadataValue<VE>> for MetadataValue<VE> {
531    #[inline]
532    fn from(t: &'a MetadataValue<VE>) -> Self {
533        t.clone()
534    }
535}
536
537// ===== ToStrError =====
538
539impl ToStrError {
540    pub(crate) fn new() -> Self {
541        Self { _priv: () }
542    }
543}
544
545impl fmt::Display for ToStrError {
546    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
547        f.write_str("failed to convert metadata to a str")
548    }
549}
550
551impl Error for ToStrError {}
552
553impl Hash for MetadataValue<Ascii> {
554    fn hash<H: Hasher>(&self, state: &mut H) {
555        self.inner.hash(state)
556    }
557}
558
559impl Hash for MetadataValue<Binary> {
560    fn hash<H: Hasher>(&self, state: &mut H) {
561        match self.to_bytes() {
562            Ok(b) => b.hash(state),
563            Err(e) => e.hash(state),
564        }
565    }
566}
567
568// ===== PartialEq / PartialOrd =====
569
570impl<VE: ValueEncoding> PartialEq for MetadataValue<VE> {
571    #[inline]
572    fn eq(&self, other: &MetadataValue<VE>) -> bool {
573        // Note: Different binary strings that after base64 decoding
574        // will count as the same value for Binary values. Also,
575        // different invalid base64 values count as equal for Binary
576        // values.
577        VE::values_equal(&self.inner, &other.inner)
578    }
579}
580
581impl<VE: ValueEncoding> Eq for MetadataValue<VE> {}
582
583impl<VE: ValueEncoding> PartialOrd for MetadataValue<VE> {
584    #[inline]
585    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
586        Some(self.cmp(other))
587    }
588}
589
590impl<VE: ValueEncoding> Ord for MetadataValue<VE> {
591    #[inline]
592    fn cmp(&self, other: &Self) -> cmp::Ordering {
593        self.inner.cmp(&other.inner)
594    }
595}
596
597impl<VE: ValueEncoding> PartialEq<str> for MetadataValue<VE> {
598    #[inline]
599    fn eq(&self, other: &str) -> bool {
600        VE::equals(&self.inner, other.as_bytes())
601    }
602}
603
604impl<VE: ValueEncoding> PartialEq<[u8]> for MetadataValue<VE> {
605    #[inline]
606    fn eq(&self, other: &[u8]) -> bool {
607        VE::equals(&self.inner, other)
608    }
609}
610
611impl<VE: ValueEncoding> PartialOrd<str> for MetadataValue<VE> {
612    #[inline]
613    fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
614        self.inner.partial_cmp(other.as_bytes())
615    }
616}
617
618impl<VE: ValueEncoding> PartialOrd<[u8]> for MetadataValue<VE> {
619    #[inline]
620    fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
621        self.inner.partial_cmp(other)
622    }
623}
624
625impl<VE: ValueEncoding> PartialEq<MetadataValue<VE>> for str {
626    #[inline]
627    fn eq(&self, other: &MetadataValue<VE>) -> bool {
628        *other == *self
629    }
630}
631
632impl<VE: ValueEncoding> PartialEq<MetadataValue<VE>> for [u8] {
633    #[inline]
634    fn eq(&self, other: &MetadataValue<VE>) -> bool {
635        *other == *self
636    }
637}
638
639impl<VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for str {
640    #[inline]
641    fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {
642        self.as_bytes().partial_cmp(other.inner.as_bytes())
643    }
644}
645
646impl<VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for [u8] {
647    #[inline]
648    fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {
649        self.partial_cmp(other.inner.as_bytes())
650    }
651}
652
653impl<VE: ValueEncoding> PartialEq<String> for MetadataValue<VE> {
654    #[inline]
655    fn eq(&self, other: &String) -> bool {
656        *self == other[..]
657    }
658}
659
660impl<VE: ValueEncoding> PartialOrd<String> for MetadataValue<VE> {
661    #[inline]
662    fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
663        self.inner.partial_cmp(other.as_bytes())
664    }
665}
666
667impl<VE: ValueEncoding> PartialEq<MetadataValue<VE>> for String {
668    #[inline]
669    fn eq(&self, other: &MetadataValue<VE>) -> bool {
670        *other == *self
671    }
672}
673
674impl<VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for String {
675    #[inline]
676    fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {
677        self.as_bytes().partial_cmp(other.inner.as_bytes())
678    }
679}
680
681impl<VE: ValueEncoding> PartialEq<MetadataValue<VE>> for &MetadataValue<VE> {
682    #[inline]
683    fn eq(&self, other: &MetadataValue<VE>) -> bool {
684        **self == *other
685    }
686}
687
688impl<VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for &MetadataValue<VE> {
689    #[inline]
690    fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {
691        (**self).partial_cmp(other)
692    }
693}
694
695impl<'a, VE: ValueEncoding, T: ?Sized> PartialEq<&'a T> for MetadataValue<VE>
696where
697    MetadataValue<VE>: PartialEq<T>,
698{
699    #[inline]
700    fn eq(&self, other: &&'a T) -> bool {
701        *self == **other
702    }
703}
704
705impl<'a, VE: ValueEncoding, T: ?Sized> PartialOrd<&'a T> for MetadataValue<VE>
706where
707    MetadataValue<VE>: PartialOrd<T>,
708{
709    #[inline]
710    fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
711        self.partial_cmp(*other)
712    }
713}
714
715impl<VE: ValueEncoding> PartialEq<MetadataValue<VE>> for &str {
716    #[inline]
717    fn eq(&self, other: &MetadataValue<VE>) -> bool {
718        *other == *self
719    }
720}
721
722impl<VE: ValueEncoding> PartialOrd<MetadataValue<VE>> for &str {
723    #[inline]
724    fn partial_cmp(&self, other: &MetadataValue<VE>) -> Option<cmp::Ordering> {
725        self.as_bytes().partial_cmp(other.inner.as_bytes())
726    }
727}
728
729#[test]
730fn test_debug() {
731    let cases = &[
732        ("hello", "\"hello\""),
733        ("hello \"world\"", "\"hello \\\"world\\\"\""),
734        ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
735    ];
736
737    for &(value, expected) in cases {
738        let val = AsciiMetadataValue::try_from_bytes(value.as_bytes()).unwrap();
739        let actual = format!("{val:?}");
740        assert_eq!(expected, actual);
741    }
742
743    let mut sensitive = AsciiMetadataValue::from_static("password");
744    sensitive.set_sensitive(true);
745    assert_eq!("Sensitive", format!("{sensitive:?}"));
746}
747
748#[test]
749fn test_is_empty() {
750    fn from_str<VE: ValueEncoding>(s: &str) -> MetadataValue<VE> {
751        MetadataValue::<VE>::unchecked_from_header_value(s.parse().unwrap())
752    }
753
754    assert!(from_str::<Ascii>("").is_empty());
755    assert!(from_str::<Binary>("").is_empty());
756    assert!(!from_str::<Ascii>("a").is_empty());
757    assert!(!from_str::<Binary>("a").is_empty());
758    assert!(!from_str::<Ascii>("=").is_empty());
759    assert!(from_str::<Binary>("=").is_empty());
760    assert!(!from_str::<Ascii>("===").is_empty());
761    assert!(from_str::<Binary>("===").is_empty());
762    assert!(!from_str::<Ascii>("=====").is_empty());
763    assert!(from_str::<Binary>("=====").is_empty());
764}
765
766#[test]
767fn test_from_shared_base64_encodes() {
768    let value = BinaryMetadataValue::from_shared(Bytes::from_static(b"Hello")).unwrap();
769    assert_eq!(value.as_encoded_bytes(), b"SGVsbG8");
770}
771
772#[test]
773fn test_value_eq_value() {
774    type Bmv = BinaryMetadataValue;
775    type Amv = AsciiMetadataValue;
776
777    assert_eq!(Amv::from_static("abc"), Amv::from_static("abc"));
778    assert_ne!(Amv::from_static("abc"), Amv::from_static("ABC"));
779
780    assert_eq!(Bmv::from_bytes(b"abc"), Bmv::from_bytes(b"abc"));
781    assert_ne!(Bmv::from_bytes(b"abc"), Bmv::from_bytes(b"ABC"));
782
783    // Padding is ignored.
784    assert_eq!(
785        Bmv::from_static("SGVsbG8hIQ=="),
786        Bmv::from_static("SGVsbG8hIQ")
787    );
788    // Invalid values are all just invalid from this point of view.
789    // SAFETY: metadata value is valid here
790    unsafe {
791        assert_eq!(
792            Bmv::from_shared_unchecked(Bytes::from_static(b"..{}")),
793            Bmv::from_shared_unchecked(Bytes::from_static(b"{}.."))
794        );
795    }
796}
797
798#[test]
799fn test_value_eq_str() {
800    type Bmv = BinaryMetadataValue;
801    type Amv = AsciiMetadataValue;
802
803    assert_eq!(Amv::from_static("abc"), "abc");
804    assert_ne!(Amv::from_static("abc"), "ABC");
805    assert_eq!("abc", Amv::from_static("abc"));
806    assert_ne!("ABC", Amv::from_static("abc"));
807
808    assert_eq!(Bmv::from_bytes(b"abc"), "abc");
809    assert_ne!(Bmv::from_bytes(b"abc"), "ABC");
810    assert_eq!("abc", Bmv::from_bytes(b"abc"));
811    assert_ne!("ABC", Bmv::from_bytes(b"abc"));
812
813    // Padding is ignored.
814    assert_eq!(Bmv::from_static("SGVsbG8hIQ=="), "Hello!!");
815    assert_eq!("Hello!!", Bmv::from_static("SGVsbG8hIQ=="));
816}
817
818#[test]
819fn test_value_eq_bytes() {
820    type Bmv = BinaryMetadataValue;
821    type Amv = AsciiMetadataValue;
822
823    assert_eq!(Amv::from_static("abc"), "abc".as_bytes());
824    assert_ne!(Amv::from_static("abc"), "ABC".as_bytes());
825    assert_eq!(*"abc".as_bytes(), Amv::from_static("abc"));
826    assert_ne!(*"ABC".as_bytes(), Amv::from_static("abc"));
827
828    assert_eq!(*"abc".as_bytes(), Bmv::from_bytes(b"abc"));
829    assert_ne!(*"ABC".as_bytes(), Bmv::from_bytes(b"abc"));
830
831    // Padding is ignored.
832    assert_eq!(Bmv::from_static("SGVsbG8hIQ=="), "Hello!!".as_bytes());
833    assert_eq!(*"Hello!!".as_bytes(), Bmv::from_static("SGVsbG8hIQ=="));
834}
835
836#[test]
837fn test_ascii_value_hash() {
838    use std::collections::hash_map::DefaultHasher;
839    type Amv = AsciiMetadataValue;
840
841    fn hash(value: Amv) -> u64 {
842        let mut hasher = DefaultHasher::new();
843        value.hash(&mut hasher);
844        hasher.finish()
845    }
846
847    let value1 = Amv::from_static("abc");
848    let value2 = Amv::from_static("abc");
849    assert_eq!(value1, value2);
850    assert_eq!(hash(value1), hash(value2));
851
852    let value1 = Amv::from_static("abc");
853    let value2 = Amv::from_static("xyz");
854
855    assert_ne!(value1, value2);
856    assert_ne!(hash(value1), hash(value2));
857}
858
859#[test]
860fn test_valid_binary_value_hash() {
861    use std::collections::hash_map::DefaultHasher;
862    type Bmv = BinaryMetadataValue;
863
864    fn hash(value: Bmv) -> u64 {
865        let mut hasher = DefaultHasher::new();
866        value.hash(&mut hasher);
867        hasher.finish()
868    }
869
870    let value1 = Bmv::from_bytes(b"abc");
871    let value2 = Bmv::from_bytes(b"abc");
872    assert_eq!(value1, value2);
873    assert_eq!(hash(value1), hash(value2));
874
875    let value1 = Bmv::from_bytes(b"abc");
876    let value2 = Bmv::from_bytes(b"xyz");
877    assert_ne!(value1, value2);
878    assert_ne!(hash(value1), hash(value2));
879}
880
881#[test]
882fn test_invalid_binary_value_hash() {
883    use std::collections::hash_map::DefaultHasher;
884    type Bmv = BinaryMetadataValue;
885
886    fn hash(value: Bmv) -> u64 {
887        let mut hasher = DefaultHasher::new();
888        value.hash(&mut hasher);
889        hasher.finish()
890    }
891
892    // SAFETY: metadata value is valid here
893    unsafe {
894        let value1 = Bmv::from_shared_unchecked(Bytes::from_static(b"..{}"));
895        let value2 = Bmv::from_shared_unchecked(Bytes::from_static(b"{}.."));
896        assert_eq!(value1, value2);
897        assert_eq!(hash(value1), hash(value2));
898    }
899
900    // SAFETY: metadata value is valid here
901    unsafe {
902        let valid = Bmv::from_bytes(b"abc");
903        let invalid = Bmv::from_shared_unchecked(Bytes::from_static(b"{}.."));
904        assert_ne!(valid, invalid);
905        assert_ne!(hash(valid), hash(invalid));
906    }
907}