tower_grpc/metadata/
value.rs

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