Skip to main content

tonic/metadata/
value.rs

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