tonic/metadata/
value.rs

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