pub(crate) use self::as_encoding_agnostic_metadata_key::AsEncodingAgnosticMetadataKey; pub(crate) use self::as_metadata_key::AsMetadataKey; pub(crate) use self::into_metadata_key::IntoMetadataKey; use super::encoding::{Ascii, Binary, ValueEncoding}; use super::key::{InvalidMetadataKey, MetadataKey}; use super::value::MetadataValue; use std::marker::PhantomData; /// A set of gRPC custom metadata entries. /// /// # Examples /// /// Basic usage /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// map.insert("x-host", "example.com".parse().unwrap()); /// map.insert("x-number", "123".parse().unwrap()); /// map.insert_bin("trace-proto-bin", MetadataValue::from_bytes(b"[binary data]")); /// /// assert!(map.contains_key("x-host")); /// assert!(!map.contains_key("x-location")); /// /// assert_eq!(map.get("x-host").unwrap(), "example.com"); /// /// map.remove("x-host"); /// /// assert!(!map.contains_key("x-host")); /// ``` #[derive(Clone, Debug, Default)] pub struct MetadataMap { headers: http::HeaderMap, } /// `MetadataMap` entry iterator. /// /// Yields `KeyAndValueRef` values. The same header name may be yielded /// more than once if it has more than one associated value. #[derive(Debug)] pub struct Iter<'a> { inner: http::header::Iter<'a, http::header::HeaderValue>, } /// Reference to a key and an associated value in a `MetadataMap`. It can point /// to either an ascii or a binary ("*-bin") key. #[derive(Debug)] pub enum KeyAndValueRef<'a> { /// An ascii metadata key and value. Ascii(&'a MetadataKey, &'a MetadataValue), /// A binary metadata key and value. Binary(&'a MetadataKey, &'a MetadataValue), } /// Reference to a key and an associated value in a `MetadataMap`. It can point /// to either an ascii or a binary ("*-bin") key. #[derive(Debug)] pub enum KeyAndMutValueRef<'a> { /// An ascii metadata key and value. Ascii(&'a MetadataKey, &'a mut MetadataValue), /// A binary metadata key and value. Binary(&'a MetadataKey, &'a mut MetadataValue), } /// `MetadataMap` entry iterator. /// /// Yields `(&MetadataKey, &mut value)` tuples. The same header name may be yielded /// more than once if it has more than one associated value. #[derive(Debug)] pub struct IterMut<'a> { inner: http::header::IterMut<'a, http::header::HeaderValue>, } /// A drain iterator of all values associated with a single metadata key. #[derive(Debug)] pub struct ValueDrain<'a, VE: ValueEncoding> { inner: http::header::ValueDrain<'a, http::header::HeaderValue>, phantom: PhantomData, } /// An iterator over `MetadataMap` keys. /// /// Yields `KeyRef` values. Each header name is yielded only once, even if it /// has more than one associated value. #[derive(Debug)] pub struct Keys<'a> { inner: http::header::Keys<'a, http::header::HeaderValue>, } /// Reference to a key in a `MetadataMap`. It can point /// to either an ascii or a binary ("*-bin") key. #[derive(Debug)] pub enum KeyRef<'a> { /// An ascii metadata key and value. Ascii(&'a MetadataKey), /// A binary metadata key and value. Binary(&'a MetadataKey), } /// `MetadataMap` value iterator. /// /// Yields `ValueRef` values. Each value contained in the `MetadataMap` will be /// yielded. #[derive(Debug)] pub struct Values<'a> { // Need to use http::header::Iter and not http::header::Values to be able // to know if a value is binary or not. inner: http::header::Iter<'a, http::header::HeaderValue>, } /// Reference to a value in a `MetadataMap`. It can point /// to either an ascii or a binary ("*-bin" key) value. #[derive(Debug)] pub enum ValueRef<'a> { /// An ascii metadata key and value. Ascii(&'a MetadataValue), /// A binary metadata key and value. Binary(&'a MetadataValue), } /// `MetadataMap` value iterator. /// /// Each value contained in the `MetadataMap` will be yielded. #[derive(Debug)] pub struct ValuesMut<'a> { // Need to use http::header::IterMut and not http::header::ValuesMut to be // able to know if a value is binary or not. inner: http::header::IterMut<'a, http::header::HeaderValue>, } /// Reference to a value in a `MetadataMap`. It can point /// to either an ascii or a binary ("*-bin" key) value. #[derive(Debug)] pub enum ValueRefMut<'a> { /// An ascii metadata key and value. Ascii(&'a mut MetadataValue), /// A binary metadata key and value. Binary(&'a mut MetadataValue), } /// An iterator of all values associated with a single metadata key. #[derive(Debug)] pub struct ValueIter<'a, VE: ValueEncoding> { inner: Option>, phantom: PhantomData, } /// An iterator of all values associated with a single metadata key. #[derive(Debug)] pub struct ValueIterMut<'a, VE: ValueEncoding> { inner: http::header::ValueIterMut<'a, http::header::HeaderValue>, phantom: PhantomData, } /// A view to all values stored in a single entry. /// /// This struct is returned by `MetadataMap::get_all` and /// `MetadataMap::get_all_bin`. #[derive(Debug)] pub struct GetAll<'a, VE: ValueEncoding> { inner: Option>, phantom: PhantomData, } /// A view into a single location in a `MetadataMap`, which may be vacant or /// occupied. #[derive(Debug)] pub enum Entry<'a, VE: ValueEncoding> { /// An occupied entry Occupied(OccupiedEntry<'a, VE>), /// A vacant entry Vacant(VacantEntry<'a, VE>), } /// A view into a single empty location in a `MetadataMap`. /// /// This struct is returned as part of the `Entry` enum. #[derive(Debug)] pub struct VacantEntry<'a, VE: ValueEncoding> { inner: http::header::VacantEntry<'a, http::header::HeaderValue>, phantom: PhantomData, } /// A view into a single occupied location in a `MetadataMap`. /// /// This struct is returned as part of the `Entry` enum. #[derive(Debug)] pub struct OccupiedEntry<'a, VE: ValueEncoding> { inner: http::header::OccupiedEntry<'a, http::header::HeaderValue>, phantom: PhantomData, } pub(crate) const GRPC_TIMEOUT_HEADER: &str = "grpc-timeout"; // ===== impl MetadataMap ===== impl MetadataMap { // Headers reserved by the gRPC protocol. pub(crate) const GRPC_RESERVED_HEADERS: [&'static str; 6] = [ "te", "user-agent", "content-type", "grpc-message", "grpc-message-type", "grpc-status", ]; /// Create an empty `MetadataMap`. /// /// The map will be created without any capacity. This function will not /// allocate. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let map = MetadataMap::new(); /// /// assert!(map.is_empty()); /// assert_eq!(0, map.capacity()); /// ``` pub fn new() -> Self { MetadataMap::with_capacity(0) } /// Convert an HTTP HeaderMap to a MetadataMap pub fn from_headers(headers: http::HeaderMap) -> Self { MetadataMap { headers } } /// Convert a MetadataMap into a HTTP HeaderMap /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.insert("x-host", "example.com".parse().unwrap()); /// /// let http_map = map.into_headers(); /// /// assert_eq!(http_map.get("x-host").unwrap(), "example.com"); /// ``` pub fn into_headers(self) -> http::HeaderMap { self.headers } pub(crate) fn into_sanitized_headers(mut self) -> http::HeaderMap { for r in &Self::GRPC_RESERVED_HEADERS { self.headers.remove(*r); } self.headers } /// Create an empty `MetadataMap` with the specified capacity. /// /// The returned map will allocate internal storage in order to hold about /// `capacity` elements without reallocating. However, this is a "best /// effort" as there are usage patterns that could cause additional /// allocations before `capacity` metadata entries are stored in the map. /// /// More capacity than requested may be allocated. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let map: MetadataMap = MetadataMap::with_capacity(10); /// /// assert!(map.is_empty()); /// assert!(map.capacity() >= 10); /// ``` pub fn with_capacity(capacity: usize) -> MetadataMap { MetadataMap { headers: http::HeaderMap::with_capacity(capacity), } } /// Returns the number of metadata entries (ascii and binary) stored in the /// map. /// /// This number represents the total number of **values** stored in the map. /// This number can be greater than or equal to the number of **keys** /// stored given that a single key may have more than one associated value. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// assert_eq!(0, map.len()); /// /// map.insert("x-host-ip", "127.0.0.1".parse().unwrap()); /// map.insert_bin("x-host-name-bin", MetadataValue::from_bytes(b"localhost")); /// /// assert_eq!(2, map.len()); /// /// map.append("x-host-ip", "text/html".parse().unwrap()); /// /// assert_eq!(3, map.len()); /// ``` pub fn len(&self) -> usize { self.headers.len() } /// Returns the number of keys (ascii and binary) stored in the map. /// /// This number will be less than or equal to `len()` as each key may have /// more than one associated value. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// assert_eq!(0, map.keys_len()); /// /// map.insert("x-host-ip", "127.0.0.1".parse().unwrap()); /// map.insert_bin("x-host-name-bin", MetadataValue::from_bytes(b"localhost")); /// /// assert_eq!(2, map.keys_len()); /// /// map.append("x-host-ip", "text/html".parse().unwrap()); /// /// assert_eq!(2, map.keys_len()); /// ``` pub fn keys_len(&self) -> usize { self.headers.keys_len() } /// Returns true if the map contains no elements. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// assert!(map.is_empty()); /// /// map.insert("x-host", "hello.world".parse().unwrap()); /// /// assert!(!map.is_empty()); /// ``` pub fn is_empty(&self) -> bool { self.headers.is_empty() } /// Clears the map, removing all key-value pairs. Keeps the allocated memory /// for reuse. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.insert("x-host", "hello.world".parse().unwrap()); /// /// map.clear(); /// assert!(map.is_empty()); /// assert!(map.capacity() > 0); /// ``` pub fn clear(&mut self) { self.headers.clear(); } /// Returns the number of custom metadata entries the map can hold without /// reallocating. /// /// This number is an approximation as certain usage patterns could cause /// additional allocations before the returned capacity is filled. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// assert_eq!(0, map.capacity()); /// /// map.insert("x-host", "hello.world".parse().unwrap()); /// assert_eq!(6, map.capacity()); /// ``` pub fn capacity(&self) -> usize { self.headers.capacity() } /// Reserves capacity for at least `additional` more custom metadata to be /// inserted into the `MetadataMap`. /// /// The metadata map may reserve more space to avoid frequent reallocations. /// Like with `with_capacity`, this will be a "best effort" to avoid /// allocations until `additional` more custom metadata is inserted. Certain /// usage patterns could cause additional allocations before the number is /// reached. /// /// # Panics /// /// Panics if the new allocation size overflows `usize`. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.reserve(10); /// # map.insert("x-host", "bar".parse().unwrap()); /// ``` pub fn reserve(&mut self, additional: usize) { self.headers.reserve(additional); } /// Returns a reference to the value associated with the key. This method /// is for ascii metadata entries (those whose names don't end with /// "-bin"). For binary entries, use get_bin. /// /// If there are multiple values associated with the key, then the first one /// is returned. Use `get_all` to get all values associated with a given /// key. Returns `None` if there are no values associated with the key. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// assert!(map.get("x-host").is_none()); /// /// map.insert("x-host", "hello".parse().unwrap()); /// assert_eq!(map.get("x-host").unwrap(), &"hello"); /// assert_eq!(map.get("x-host").unwrap(), &"hello"); /// /// map.append("x-host", "world".parse().unwrap()); /// assert_eq!(map.get("x-host").unwrap(), &"hello"); /// /// // Attempting to read a key of the wrong type fails by not /// // finding anything. /// map.append_bin("host-bin", MetadataValue::from_bytes(b"world")); /// assert!(map.get("host-bin").is_none()); /// assert!(map.get("host-bin".to_string()).is_none()); /// assert!(map.get(&("host-bin".to_string())).is_none()); /// /// // Attempting to read an invalid key string fails by not /// // finding anything. /// assert!(map.get("host{}bin").is_none()); /// assert!(map.get("host{}bin".to_string()).is_none()); /// assert!(map.get(&("host{}bin".to_string())).is_none()); /// ``` pub fn get(&self, key: K) -> Option<&MetadataValue> where K: AsMetadataKey, { key.get(self) } /// Like get, but for Binary keys (for example "trace-proto-bin"). /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// assert!(map.get_bin("trace-proto-bin").is_none()); /// /// map.insert_bin("trace-proto-bin", MetadataValue::from_bytes(b"hello")); /// assert_eq!(map.get_bin("trace-proto-bin").unwrap(), &"hello"); /// assert_eq!(map.get_bin("trace-proto-bin").unwrap(), &"hello"); /// /// map.append_bin("trace-proto-bin", MetadataValue::from_bytes(b"world")); /// assert_eq!(map.get_bin("trace-proto-bin").unwrap(), &"hello"); /// /// // Attempting to read a key of the wrong type fails by not /// // finding anything. /// map.append("host", "world".parse().unwrap()); /// assert!(map.get_bin("host").is_none()); /// assert!(map.get_bin("host".to_string()).is_none()); /// assert!(map.get_bin(&("host".to_string())).is_none()); /// /// // Attempting to read an invalid key string fails by not /// // finding anything. /// assert!(map.get_bin("host{}-bin").is_none()); /// assert!(map.get_bin("host{}-bin".to_string()).is_none()); /// assert!(map.get_bin(&("host{}-bin".to_string())).is_none()); /// ``` pub fn get_bin(&self, key: K) -> Option<&MetadataValue> where K: AsMetadataKey, { key.get(self) } /// Returns a mutable reference to the value associated with the key. This /// method is for ascii metadata entries (those whose names don't end with /// "-bin"). For binary entries, use get_mut_bin. /// /// If there are multiple values associated with the key, then the first one /// is returned. Use `entry` to get all values associated with a given /// key. Returns `None` if there are no values associated with the key. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::default(); /// map.insert("x-host", "hello".parse().unwrap()); /// map.get_mut("x-host").unwrap().set_sensitive(true); /// /// assert!(map.get("x-host").unwrap().is_sensitive()); /// /// // Attempting to read a key of the wrong type fails by not /// // finding anything. /// map.append_bin("host-bin", MetadataValue::from_bytes(b"world")); /// assert!(map.get_mut("host-bin").is_none()); /// assert!(map.get_mut("host-bin".to_string()).is_none()); /// assert!(map.get_mut(&("host-bin".to_string())).is_none()); /// /// // Attempting to read an invalid key string fails by not /// // finding anything. /// assert!(map.get_mut("host{}").is_none()); /// assert!(map.get_mut("host{}".to_string()).is_none()); /// assert!(map.get_mut(&("host{}".to_string())).is_none()); /// ``` pub fn get_mut(&mut self, key: K) -> Option<&mut MetadataValue> where K: AsMetadataKey, { key.get_mut(self) } /// Like get_mut, but for Binary keys (for example "trace-proto-bin"). /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::default(); /// map.insert_bin("trace-proto-bin", MetadataValue::from_bytes(b"hello")); /// map.get_bin_mut("trace-proto-bin").unwrap().set_sensitive(true); /// /// assert!(map.get_bin("trace-proto-bin").unwrap().is_sensitive()); /// /// // Attempting to read a key of the wrong type fails by not /// // finding anything. /// map.append("host", "world".parse().unwrap()); /// assert!(map.get_bin_mut("host").is_none()); /// assert!(map.get_bin_mut("host".to_string()).is_none()); /// assert!(map.get_bin_mut(&("host".to_string())).is_none()); /// /// // Attempting to read an invalid key string fails by not /// // finding anything. /// assert!(map.get_bin_mut("host{}-bin").is_none()); /// assert!(map.get_bin_mut("host{}-bin".to_string()).is_none()); /// assert!(map.get_bin_mut(&("host{}-bin".to_string())).is_none()); /// ``` pub fn get_bin_mut(&mut self, key: K) -> Option<&mut MetadataValue> where K: AsMetadataKey, { key.get_mut(self) } /// Returns a view of all values associated with a key. This method is for /// ascii metadata entries (those whose names don't end with "-bin"). For /// binary entries, use get_all_bin. /// /// The returned view does not incur any allocations and allows iterating /// the values associated with the key. See [`GetAll`] for more details. /// Returns `None` if there are no values associated with the key. /// /// [`GetAll`]: struct.GetAll.html /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// map.insert("x-host", "hello".parse().unwrap()); /// map.append("x-host", "goodbye".parse().unwrap()); /// /// { /// let view = map.get_all("x-host"); /// /// let mut iter = view.iter(); /// assert_eq!(&"hello", iter.next().unwrap()); /// assert_eq!(&"goodbye", iter.next().unwrap()); /// assert!(iter.next().is_none()); /// } /// /// // Attempting to read a key of the wrong type fails by not /// // finding anything. /// map.append_bin("host-bin", MetadataValue::from_bytes(b"world")); /// assert!(map.get_all("host-bin").iter().next().is_none()); /// assert!(map.get_all("host-bin".to_string()).iter().next().is_none()); /// assert!(map.get_all(&("host-bin".to_string())).iter().next().is_none()); /// /// // Attempting to read an invalid key string fails by not /// // finding anything. /// assert!(map.get_all("host{}").iter().next().is_none()); /// assert!(map.get_all("host{}".to_string()).iter().next().is_none()); /// assert!(map.get_all(&("host{}".to_string())).iter().next().is_none()); /// ``` pub fn get_all(&self, key: K) -> GetAll<'_, Ascii> where K: AsMetadataKey, { GetAll { inner: key.get_all(self), phantom: PhantomData, } } /// Like get_all, but for Binary keys (for example "trace-proto-bin"). /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// map.insert_bin("trace-proto-bin", MetadataValue::from_bytes(b"hello")); /// map.append_bin("trace-proto-bin", MetadataValue::from_bytes(b"goodbye")); /// /// { /// let view = map.get_all_bin("trace-proto-bin"); /// /// let mut iter = view.iter(); /// assert_eq!(&"hello", iter.next().unwrap()); /// assert_eq!(&"goodbye", iter.next().unwrap()); /// assert!(iter.next().is_none()); /// } /// /// // Attempting to read a key of the wrong type fails by not /// // finding anything. /// map.append("host", "world".parse().unwrap()); /// assert!(map.get_all_bin("host").iter().next().is_none()); /// assert!(map.get_all_bin("host".to_string()).iter().next().is_none()); /// assert!(map.get_all_bin(&("host".to_string())).iter().next().is_none()); /// /// // Attempting to read an invalid key string fails by not /// // finding anything. /// assert!(map.get_all_bin("host{}-bin").iter().next().is_none()); /// assert!(map.get_all_bin("host{}-bin".to_string()).iter().next().is_none()); /// assert!(map.get_all_bin(&("host{}-bin".to_string())).iter().next().is_none()); /// ``` pub fn get_all_bin(&self, key: K) -> GetAll<'_, Binary> where K: AsMetadataKey, { GetAll { inner: key.get_all(self), phantom: PhantomData, } } /// Returns true if the map contains a value for the specified key. This /// method works for both ascii and binary entries. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// assert!(!map.contains_key("x-host")); /// /// map.append_bin("host-bin", MetadataValue::from_bytes(b"world")); /// map.insert("x-host", "world".parse().unwrap()); /// /// // contains_key works for both Binary and Ascii keys: /// assert!(map.contains_key("x-host")); /// assert!(map.contains_key("host-bin")); /// /// // contains_key returns false for invalid keys: /// assert!(!map.contains_key("x{}host")); /// ``` pub fn contains_key(&self, key: K) -> bool where K: AsEncodingAgnosticMetadataKey, { key.contains_key(self) } /// An iterator visiting all key-value pairs (both ascii and binary). /// /// The iteration order is arbitrary, but consistent across platforms for /// the same crate version. Each key will be yielded once per associated /// value. So, if a key has 3 associated values, it will be yielded 3 times. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// map.insert("x-word", "hello".parse().unwrap()); /// map.append("x-word", "goodbye".parse().unwrap()); /// map.insert("x-number", "123".parse().unwrap()); /// /// for key_and_value in map.iter() { /// match key_and_value { /// KeyAndValueRef::Ascii(ref key, ref value) => /// println!("Ascii: {:?}: {:?}", key, value), /// KeyAndValueRef::Binary(ref key, ref value) => /// println!("Binary: {:?}: {:?}", key, value), /// } /// } /// ``` pub fn iter(&self) -> Iter<'_> { Iter { inner: self.headers.iter(), } } /// An iterator visiting all key-value pairs, with mutable value references. /// /// The iterator order is arbitrary, but consistent across platforms for the /// same crate version. Each key will be yielded once per associated value, /// so if a key has 3 associated values, it will be yielded 3 times. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// map.insert("x-word", "hello".parse().unwrap()); /// map.append("x-word", "goodbye".parse().unwrap()); /// map.insert("x-number", "123".parse().unwrap()); /// /// for key_and_value in map.iter_mut() { /// match key_and_value { /// KeyAndMutValueRef::Ascii(key, mut value) => /// value.set_sensitive(true), /// KeyAndMutValueRef::Binary(key, mut value) => /// value.set_sensitive(false), /// } /// } /// ``` pub fn iter_mut(&mut self) -> IterMut<'_> { IterMut { inner: self.headers.iter_mut(), } } /// An iterator visiting all keys. /// /// The iteration order is arbitrary, but consistent across platforms for /// the same crate version. Each key will be yielded only once even if it /// has multiple associated values. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// map.insert("x-word", "hello".parse().unwrap()); /// map.append("x-word", "goodbye".parse().unwrap()); /// map.insert_bin("x-number-bin", MetadataValue::from_bytes(b"123")); /// /// for key in map.keys() { /// match key { /// KeyRef::Ascii(ref key) => /// println!("Ascii key: {:?}", key), /// KeyRef::Binary(ref key) => /// println!("Binary key: {:?}", key), /// } /// println!("{:?}", key); /// } /// ``` pub fn keys(&self) -> Keys<'_> { Keys { inner: self.headers.keys(), } } /// An iterator visiting all values (both ascii and binary). /// /// The iteration order is arbitrary, but consistent across platforms for /// the same crate version. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// map.insert("x-word", "hello".parse().unwrap()); /// map.append("x-word", "goodbye".parse().unwrap()); /// map.insert_bin("x-number-bin", MetadataValue::from_bytes(b"123")); /// /// for value in map.values() { /// match value { /// ValueRef::Ascii(ref value) => /// println!("Ascii value: {:?}", value), /// ValueRef::Binary(ref value) => /// println!("Binary value: {:?}", value), /// } /// println!("{:?}", value); /// } /// ``` pub fn values(&self) -> Values<'_> { Values { inner: self.headers.iter(), } } /// An iterator visiting all values mutably. /// /// The iteration order is arbitrary, but consistent across platforms for /// the same crate version. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::default(); /// /// map.insert("x-word", "hello".parse().unwrap()); /// map.append("x-word", "goodbye".parse().unwrap()); /// map.insert("x-number", "123".parse().unwrap()); /// /// for value in map.values_mut() { /// match value { /// ValueRefMut::Ascii(mut value) => /// value.set_sensitive(true), /// ValueRefMut::Binary(mut value) => /// value.set_sensitive(false), /// } /// } /// ``` pub fn values_mut(&mut self) -> ValuesMut<'_> { ValuesMut { inner: self.headers.iter_mut(), } } /// Gets the given ascii key's corresponding entry in the map for in-place /// manipulation. For binary keys, use `entry_bin`. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::default(); /// /// let headers = &[ /// "content-length", /// "x-hello", /// "Content-Length", /// "x-world", /// ]; /// /// for &header in headers { /// let counter = map.entry(header).unwrap().or_insert("".parse().unwrap()); /// *counter = format!("{}{}", counter.to_str().unwrap(), "1").parse().unwrap(); /// } /// /// assert_eq!(map.get("content-length").unwrap(), "11"); /// assert_eq!(map.get("x-hello").unwrap(), "1"); /// /// // Gracefully handles parting invalid key strings /// assert!(!map.entry("a{}b").is_ok()); /// /// // Attempting to read a key of the wrong type fails by not /// // finding anything. /// map.append_bin("host-bin", MetadataValue::from_bytes(b"world")); /// assert!(!map.entry("host-bin").is_ok()); /// assert!(!map.entry("host-bin".to_string()).is_ok()); /// assert!(!map.entry(&("host-bin".to_string())).is_ok()); /// /// // Attempting to read an invalid key string fails by not /// // finding anything. /// assert!(!map.entry("host{}").is_ok()); /// assert!(!map.entry("host{}".to_string()).is_ok()); /// assert!(!map.entry(&("host{}".to_string())).is_ok()); /// ``` pub fn entry(&mut self, key: K) -> Result, InvalidMetadataKey> where K: AsMetadataKey, { self.generic_entry::(key) } /// Gets the given Binary key's corresponding entry in the map for in-place /// manipulation. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// # use std::str; /// let mut map = MetadataMap::default(); /// /// let headers = &[ /// "content-length-bin", /// "x-hello-bin", /// "Content-Length-bin", /// "x-world-bin", /// ]; /// /// for &header in headers { /// let counter = map.entry_bin(header).unwrap().or_insert(MetadataValue::from_bytes(b"")); /// *counter = MetadataValue::from_bytes(format!("{}{}", str::from_utf8(counter.to_bytes().unwrap().as_ref()).unwrap(), "1").as_bytes()); /// } /// /// assert_eq!(map.get_bin("content-length-bin").unwrap(), "11"); /// assert_eq!(map.get_bin("x-hello-bin").unwrap(), "1"); /// /// // Attempting to read a key of the wrong type fails by not /// // finding anything. /// map.append("host", "world".parse().unwrap()); /// assert!(!map.entry_bin("host").is_ok()); /// assert!(!map.entry_bin("host".to_string()).is_ok()); /// assert!(!map.entry_bin(&("host".to_string())).is_ok()); /// /// // Attempting to read an invalid key string fails by not /// // finding anything. /// assert!(!map.entry_bin("host{}-bin").is_ok()); /// assert!(!map.entry_bin("host{}-bin".to_string()).is_ok()); /// assert!(!map.entry_bin(&("host{}-bin".to_string())).is_ok()); /// ``` pub fn entry_bin(&mut self, key: K) -> Result, InvalidMetadataKey> where K: AsMetadataKey, { self.generic_entry::(key) } fn generic_entry( &mut self, key: K, ) -> Result, InvalidMetadataKey> where K: AsMetadataKey, { match key.entry(self) { Ok(entry) => Ok(match entry { http::header::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry { inner: e, phantom: PhantomData, }), http::header::Entry::Vacant(e) => Entry::Vacant(VacantEntry { inner: e, phantom: PhantomData, }), }), Err(err) => Err(err), } } /// Inserts an ascii key-value pair into the map. To insert a binary entry, /// use `insert_bin`. /// /// This method panics when the given key is a string and it cannot be /// converted to a `MetadataKey`. /// /// If the map did not previously have this key present, then `None` is /// returned. /// /// If the map did have this key present, the new value is associated with /// the key and all previous values are removed. **Note** that only a single /// one of the previous values is returned. If there are multiple values /// that have been previously associated with the key, then the first one is /// returned. See `insert_mult` on `OccupiedEntry` for an API that returns /// all values. /// /// The key is not updated, though; this matters for types that can be `==` /// without being identical. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// assert!(map.insert("x-host", "world".parse().unwrap()).is_none()); /// assert!(!map.is_empty()); /// /// let mut prev = map.insert("x-host", "earth".parse().unwrap()).unwrap(); /// assert_eq!("world", prev); /// ``` /// /// ```should_panic /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// // Trying to insert a key that is not valid panics. /// map.insert("x{}host", "world".parse().unwrap()); /// ``` /// /// ```should_panic /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// // Trying to insert a key that is binary panics (use insert_bin). /// map.insert("x-host-bin", "world".parse().unwrap()); /// ``` pub fn insert(&mut self, key: K, val: MetadataValue) -> Option> where K: IntoMetadataKey, { key.insert(self, val) } /// Like insert, but for Binary keys (for example "trace-proto-bin"). /// /// This method panics when the given key is a string and it cannot be /// converted to a `MetadataKey`. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// assert!(map.insert_bin("trace-proto-bin", MetadataValue::from_bytes(b"world")).is_none()); /// assert!(!map.is_empty()); /// /// let mut prev = map.insert_bin("trace-proto-bin", MetadataValue::from_bytes(b"earth")).unwrap(); /// assert_eq!("world", prev); /// ``` /// /// ```should_panic /// # use tonic::metadata::*; /// let mut map = MetadataMap::default(); /// // Attempting to add a binary metadata entry with an invalid name /// map.insert_bin("trace-proto", MetadataValue::from_bytes(b"hello")); // This line panics! /// ``` /// /// ```should_panic /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// // Trying to insert a key that is not valid panics. /// map.insert_bin("x{}host-bin", MetadataValue::from_bytes(b"world")); // This line panics! /// ``` pub fn insert_bin( &mut self, key: K, val: MetadataValue, ) -> Option> where K: IntoMetadataKey, { key.insert(self, val) } /// Inserts an ascii key-value pair into the map. To insert a binary entry, /// use `append_bin`. /// /// This method panics when the given key is a string and it cannot be /// converted to a `MetadataKey`. /// /// If the map did not previously have this key present, then `false` is /// returned. /// /// If the map did have this key present, the new value is pushed to the end /// of the list of values currently associated with the key. The key is not /// updated, though; this matters for types that can be `==` without being /// identical. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// assert!(map.insert("x-host", "world".parse().unwrap()).is_none()); /// assert!(!map.is_empty()); /// /// map.append("x-host", "earth".parse().unwrap()); /// /// let values = map.get_all("x-host"); /// let mut i = values.iter(); /// assert_eq!("world", *i.next().unwrap()); /// assert_eq!("earth", *i.next().unwrap()); /// ``` /// /// ```should_panic /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// // Trying to append a key that is not valid panics. /// map.append("x{}host", "world".parse().unwrap()); // This line panics! /// ``` /// /// ```should_panic /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// // Trying to append a key that is binary panics (use append_bin). /// map.append("x-host-bin", "world".parse().unwrap()); // This line panics! /// ``` pub fn append(&mut self, key: K, value: MetadataValue) -> bool where K: IntoMetadataKey, { key.append(self, value) } /// Like append, but for binary keys (for example "trace-proto-bin"). /// /// This method panics when the given key is a string and it cannot be /// converted to a `MetadataKey`. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// assert!(map.insert_bin("trace-proto-bin", MetadataValue::from_bytes(b"world")).is_none()); /// assert!(!map.is_empty()); /// /// map.append_bin("trace-proto-bin", MetadataValue::from_bytes(b"earth")); /// /// let values = map.get_all_bin("trace-proto-bin"); /// let mut i = values.iter(); /// assert_eq!("world", *i.next().unwrap()); /// assert_eq!("earth", *i.next().unwrap()); /// ``` /// /// ```should_panic /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// // Trying to append a key that is not valid panics. /// map.append_bin("x{}host-bin", MetadataValue::from_bytes(b"world")); // This line panics! /// ``` /// /// ```should_panic /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// // Trying to append a key that is ascii panics (use append). /// map.append_bin("x-host", MetadataValue::from_bytes(b"world")); // This line panics! /// ``` pub fn append_bin(&mut self, key: K, value: MetadataValue) -> bool where K: IntoMetadataKey, { key.append(self, value) } /// Removes an ascii key from the map, returning the value associated with /// the key. To remove a binary key, use `remove_bin`. /// /// Returns `None` if the map does not contain the key. If there are /// multiple values associated with the key, then the first one is returned. /// See `remove_entry_mult` on `OccupiedEntry` for an API that yields all /// values. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.insert("x-host", "hello.world".parse().unwrap()); /// /// let prev = map.remove("x-host").unwrap(); /// assert_eq!("hello.world", prev); /// /// assert!(map.remove("x-host").is_none()); /// /// // Attempting to remove a key of the wrong type fails by not /// // finding anything. /// map.append_bin("host-bin", MetadataValue::from_bytes(b"world")); /// assert!(map.remove("host-bin").is_none()); /// assert!(map.remove("host-bin".to_string()).is_none()); /// assert!(map.remove(&("host-bin".to_string())).is_none()); /// /// // Attempting to remove an invalid key string fails by not /// // finding anything. /// assert!(map.remove("host{}").is_none()); /// assert!(map.remove("host{}".to_string()).is_none()); /// assert!(map.remove(&("host{}".to_string())).is_none()); /// ``` pub fn remove(&mut self, key: K) -> Option> where K: AsMetadataKey, { key.remove(self) } /// Like remove, but for Binary keys (for example "trace-proto-bin"). /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.insert_bin("trace-proto-bin", MetadataValue::from_bytes(b"hello.world")); /// /// let prev = map.remove_bin("trace-proto-bin").unwrap(); /// assert_eq!("hello.world", prev); /// /// assert!(map.remove_bin("trace-proto-bin").is_none()); /// /// // Attempting to remove a key of the wrong type fails by not /// // finding anything. /// map.append("host", "world".parse().unwrap()); /// assert!(map.remove_bin("host").is_none()); /// assert!(map.remove_bin("host".to_string()).is_none()); /// assert!(map.remove_bin(&("host".to_string())).is_none()); /// /// // Attempting to remove an invalid key string fails by not /// // finding anything. /// assert!(map.remove_bin("host{}-bin").is_none()); /// assert!(map.remove_bin("host{}-bin".to_string()).is_none()); /// assert!(map.remove_bin(&("host{}-bin".to_string())).is_none()); /// ``` pub fn remove_bin(&mut self, key: K) -> Option> where K: AsMetadataKey, { key.remove(self) } pub(crate) fn merge(&mut self, other: MetadataMap) { self.headers.extend(other.headers); } } // ===== impl Iter ===== impl<'a> Iterator for Iter<'a> { type Item = KeyAndValueRef<'a>; fn next(&mut self) -> Option { self.inner.next().map(|item| { let (name, value) = item; if Ascii::is_valid_key(name.as_str()) { KeyAndValueRef::Ascii( MetadataKey::unchecked_from_header_name_ref(name), MetadataValue::unchecked_from_header_value_ref(value), ) } else { KeyAndValueRef::Binary( MetadataKey::unchecked_from_header_name_ref(name), MetadataValue::unchecked_from_header_value_ref(value), ) } }) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } // ===== impl IterMut ===== impl<'a> Iterator for IterMut<'a> { type Item = KeyAndMutValueRef<'a>; fn next(&mut self) -> Option { self.inner.next().map(|item| { let (name, value) = item; if Ascii::is_valid_key(name.as_str()) { KeyAndMutValueRef::Ascii( MetadataKey::unchecked_from_header_name_ref(name), MetadataValue::unchecked_from_mut_header_value_ref(value), ) } else { KeyAndMutValueRef::Binary( MetadataKey::unchecked_from_header_name_ref(name), MetadataValue::unchecked_from_mut_header_value_ref(value), ) } }) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } // ===== impl ValueDrain ===== impl<'a, VE: ValueEncoding> Iterator for ValueDrain<'a, VE> { type Item = MetadataValue; fn next(&mut self) -> Option { self.inner .next() .map(MetadataValue::unchecked_from_header_value) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } // ===== impl Keys ===== impl<'a> Iterator for Keys<'a> { type Item = KeyRef<'a>; fn next(&mut self) -> Option { self.inner.next().map(|key| { if Ascii::is_valid_key(key.as_str()) { KeyRef::Ascii(MetadataKey::unchecked_from_header_name_ref(key)) } else { KeyRef::Binary(MetadataKey::unchecked_from_header_name_ref(key)) } }) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } impl<'a> ExactSizeIterator for Keys<'a> {} // ===== impl Values ==== impl<'a> Iterator for Values<'a> { type Item = ValueRef<'a>; fn next(&mut self) -> Option { self.inner.next().map(|item| { let (name, value) = item; if Ascii::is_valid_key(name.as_str()) { ValueRef::Ascii(MetadataValue::unchecked_from_header_value_ref(value)) } else { ValueRef::Binary(MetadataValue::unchecked_from_header_value_ref(value)) } }) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } // ===== impl Values ==== impl<'a> Iterator for ValuesMut<'a> { type Item = ValueRefMut<'a>; fn next(&mut self) -> Option { self.inner.next().map(|item| { let (name, value) = item; if Ascii::is_valid_key(name.as_str()) { ValueRefMut::Ascii(MetadataValue::unchecked_from_mut_header_value_ref(value)) } else { ValueRefMut::Binary(MetadataValue::unchecked_from_mut_header_value_ref(value)) } }) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } // ===== impl ValueIter ===== impl<'a, VE: ValueEncoding> Iterator for ValueIter<'a, VE> where VE: 'a, { type Item = &'a MetadataValue; fn next(&mut self) -> Option { match self.inner { Some(ref mut inner) => inner .next() .map(MetadataValue::unchecked_from_header_value_ref), None => None, } } fn size_hint(&self) -> (usize, Option) { match self.inner { Some(ref inner) => inner.size_hint(), None => (0, Some(0)), } } } impl<'a, VE: ValueEncoding> DoubleEndedIterator for ValueIter<'a, VE> where VE: 'a, { fn next_back(&mut self) -> Option { match self.inner { Some(ref mut inner) => inner .next_back() .map(MetadataValue::unchecked_from_header_value_ref), None => None, } } } // ===== impl ValueIterMut ===== impl<'a, VE: ValueEncoding> Iterator for ValueIterMut<'a, VE> where VE: 'a, { type Item = &'a mut MetadataValue; fn next(&mut self) -> Option { self.inner .next() .map(MetadataValue::unchecked_from_mut_header_value_ref) } } impl<'a, VE: ValueEncoding> DoubleEndedIterator for ValueIterMut<'a, VE> where VE: 'a, { fn next_back(&mut self) -> Option { self.inner .next_back() .map(MetadataValue::unchecked_from_mut_header_value_ref) } } // ===== impl Entry ===== impl<'a, VE: ValueEncoding> Entry<'a, VE> { /// Ensures a value is in the entry by inserting the default if empty. /// /// Returns a mutable reference to the **first** value in the entry. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map: MetadataMap = MetadataMap::default(); /// /// let keys = &[ /// "content-length", /// "x-hello", /// "Content-Length", /// "x-world", /// ]; /// /// for &key in keys { /// let counter = map.entry(key) /// .expect("valid key names") /// .or_insert("".parse().unwrap()); /// *counter = format!("{}{}", counter.to_str().unwrap(), "1").parse().unwrap(); /// } /// /// assert_eq!(map.get("content-length").unwrap(), "11"); /// assert_eq!(map.get("x-hello").unwrap(), "1"); /// ``` pub fn or_insert(self, default: MetadataValue) -> &'a mut MetadataValue { use self::Entry::*; match self { Occupied(e) => e.into_mut(), Vacant(e) => e.insert(default), } } /// Ensures a value is in the entry by inserting the result of the default /// function if empty. /// /// The default function is not called if the entry exists in the map. /// Returns a mutable reference to the **first** value in the entry. /// /// # Examples /// /// Basic usage. /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// let res = map.entry("x-hello").unwrap() /// .or_insert_with(|| "world".parse().unwrap()); /// /// assert_eq!(res, "world"); /// ``` /// /// The default function is not called if the entry exists in the map. /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.insert("host", "world".parse().unwrap()); /// /// let res = map.entry("host") /// .expect("host is a valid string") /// .or_insert_with(|| unreachable!()); /// /// /// assert_eq!(res, "world"); /// ``` pub fn or_insert_with MetadataValue>( self, default: F, ) -> &'a mut MetadataValue { use self::Entry::*; match self { Occupied(e) => e.into_mut(), Vacant(e) => e.insert(default()), } } /// Returns a reference to the entry's key /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// assert_eq!(map.entry("x-hello").unwrap().key(), "x-hello"); /// ``` pub fn key(&self) -> &MetadataKey { use self::Entry::*; MetadataKey::unchecked_from_header_name_ref(match *self { Vacant(ref e) => e.inner.key(), Occupied(ref e) => e.inner.key(), }) } } // ===== impl VacantEntry ===== impl<'a, VE: ValueEncoding> VacantEntry<'a, VE> { /// Returns a reference to the entry's key /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// assert_eq!(map.entry("x-hello").unwrap().key(), "x-hello"); /// ``` pub fn key(&self) -> &MetadataKey { MetadataKey::unchecked_from_header_name_ref(self.inner.key()) } /// Take ownership of the key /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// if let Entry::Vacant(v) = map.entry("x-hello").unwrap() { /// assert_eq!(v.into_key().as_str(), "x-hello"); /// } /// ``` pub fn into_key(self) -> MetadataKey { MetadataKey::unchecked_from_header_name(self.inner.into_key()) } /// Insert the value into the entry. /// /// The value will be associated with this entry's key. A mutable reference /// to the inserted value will be returned. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// if let Entry::Vacant(v) = map.entry("x-hello").unwrap() { /// v.insert("world".parse().unwrap()); /// } /// /// assert_eq!(map.get("x-hello").unwrap(), "world"); /// ``` pub fn insert(self, value: MetadataValue) -> &'a mut MetadataValue { MetadataValue::unchecked_from_mut_header_value_ref(self.inner.insert(value.inner)) } /// Insert the value into the entry. /// /// The value will be associated with this entry's key. The new /// `OccupiedEntry` is returned, allowing for further manipulation. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// /// if let Entry::Vacant(v) = map.entry("x-hello").unwrap() { /// let mut e = v.insert_entry("world".parse().unwrap()); /// e.insert("world2".parse().unwrap()); /// } /// /// assert_eq!(map.get("x-hello").unwrap(), "world2"); /// ``` pub fn insert_entry(self, value: MetadataValue) -> OccupiedEntry<'a, Ascii> { OccupiedEntry { inner: self.inner.insert_entry(value.inner), phantom: PhantomData, } } } // ===== impl OccupiedEntry ===== impl<'a, VE: ValueEncoding> OccupiedEntry<'a, VE> { /// Returns a reference to the entry's key. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.insert("host", "world".parse().unwrap()); /// /// if let Entry::Occupied(e) = map.entry("host").unwrap() { /// assert_eq!("host", e.key()); /// } /// ``` pub fn key(&self) -> &MetadataKey { MetadataKey::unchecked_from_header_name_ref(self.inner.key()) } /// Get a reference to the first value in the entry. /// /// Values are stored in insertion order. /// /// # Panics /// /// `get` panics if there are no values associated with the entry. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.insert("host", "hello.world".parse().unwrap()); /// /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() { /// assert_eq!(e.get(), &"hello.world"); /// /// e.append("hello.earth".parse().unwrap()); /// /// assert_eq!(e.get(), &"hello.world"); /// } /// ``` pub fn get(&self) -> &MetadataValue { MetadataValue::unchecked_from_header_value_ref(self.inner.get()) } /// Get a mutable reference to the first value in the entry. /// /// Values are stored in insertion order. /// /// # Panics /// /// `get_mut` panics if there are no values associated with the entry. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::default(); /// map.insert("host", "hello.world".parse().unwrap()); /// /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() { /// e.get_mut().set_sensitive(true); /// assert_eq!(e.get(), &"hello.world"); /// assert!(e.get().is_sensitive()); /// } /// ``` pub fn get_mut(&mut self) -> &mut MetadataValue { MetadataValue::unchecked_from_mut_header_value_ref(self.inner.get_mut()) } /// Converts the `OccupiedEntry` into a mutable reference to the **first** /// value. /// /// The lifetime of the returned reference is bound to the original map. /// /// # Panics /// /// `into_mut` panics if there are no values associated with the entry. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::default(); /// map.insert("host", "hello.world".parse().unwrap()); /// map.append("host", "hello.earth".parse().unwrap()); /// /// if let Entry::Occupied(e) = map.entry("host").unwrap() { /// e.into_mut().set_sensitive(true); /// } /// /// assert!(map.get("host").unwrap().is_sensitive()); /// ``` pub fn into_mut(self) -> &'a mut MetadataValue { MetadataValue::unchecked_from_mut_header_value_ref(self.inner.into_mut()) } /// Sets the value of the entry. /// /// All previous values associated with the entry are removed and the first /// one is returned. See `insert_mult` for an API that returns all values. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.insert("host", "hello.world".parse().unwrap()); /// /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() { /// let mut prev = e.insert("earth".parse().unwrap()); /// assert_eq!("hello.world", prev); /// } /// /// assert_eq!("earth", map.get("host").unwrap()); /// ``` pub fn insert(&mut self, value: MetadataValue) -> MetadataValue { let header_value = self.inner.insert(value.inner); MetadataValue::unchecked_from_header_value(header_value) } /// Sets the value of the entry. /// /// This function does the same as `insert` except it returns an iterator /// that yields all values previously associated with the key. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.insert("host", "world".parse().unwrap()); /// map.append("host", "world2".parse().unwrap()); /// /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() { /// let mut prev = e.insert_mult("earth".parse().unwrap()); /// assert_eq!("world", prev.next().unwrap()); /// assert_eq!("world2", prev.next().unwrap()); /// assert!(prev.next().is_none()); /// } /// /// assert_eq!("earth", map.get("host").unwrap()); /// ``` pub fn insert_mult(&mut self, value: MetadataValue) -> ValueDrain<'_, VE> { ValueDrain { inner: self.inner.insert_mult(value.inner), phantom: PhantomData, } } /// Insert the value into the entry. /// /// The new value is appended to the end of the entry's value list. All /// previous values associated with the entry are retained. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.insert("host", "world".parse().unwrap()); /// /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() { /// e.append("earth".parse().unwrap()); /// } /// /// let values = map.get_all("host"); /// let mut i = values.iter(); /// assert_eq!("world", *i.next().unwrap()); /// assert_eq!("earth", *i.next().unwrap()); /// ``` pub fn append(&mut self, value: MetadataValue) { self.inner.append(value.inner) } /// Remove the entry from the map. /// /// All values associated with the entry are removed and the first one is /// returned. See `remove_entry_mult` for an API that returns all values. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.insert("host", "world".parse().unwrap()); /// /// if let Entry::Occupied(e) = map.entry("host").unwrap() { /// let mut prev = e.remove(); /// assert_eq!("world", prev); /// } /// /// assert!(!map.contains_key("host")); /// ``` pub fn remove(self) -> MetadataValue { let value = self.inner.remove(); MetadataValue::unchecked_from_header_value(value) } /// Remove the entry from the map. /// /// The key and all values associated with the entry are removed and the /// first one is returned. See `remove_entry_mult` for an API that returns /// all values. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.insert("host", "world".parse().unwrap()); /// /// if let Entry::Occupied(e) = map.entry("host").unwrap() { /// let (key, mut prev) = e.remove_entry(); /// assert_eq!("host", key.as_str()); /// assert_eq!("world", prev); /// } /// /// assert!(!map.contains_key("host")); /// ``` pub fn remove_entry(self) -> (MetadataKey, MetadataValue) { let (name, value) = self.inner.remove_entry(); ( MetadataKey::unchecked_from_header_name(name), MetadataValue::unchecked_from_header_value(value), ) } /// Remove the entry from the map. /// /// The key and all values associated with the entry are removed and /// returned. pub fn remove_entry_mult(self) -> (MetadataKey, ValueDrain<'a, VE>) { let (name, value_drain) = self.inner.remove_entry_mult(); ( MetadataKey::unchecked_from_header_name(name), ValueDrain { inner: value_drain, phantom: PhantomData, }, ) } /// Returns an iterator visiting all values associated with the entry. /// /// Values are iterated in insertion order. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.insert("host", "world".parse().unwrap()); /// map.append("host", "earth".parse().unwrap()); /// /// if let Entry::Occupied(e) = map.entry("host").unwrap() { /// let mut iter = e.iter(); /// assert_eq!(&"world", iter.next().unwrap()); /// assert_eq!(&"earth", iter.next().unwrap()); /// assert!(iter.next().is_none()); /// } /// ``` pub fn iter(&self) -> ValueIter<'_, VE> { ValueIter { inner: Some(self.inner.iter()), phantom: PhantomData, } } /// Returns an iterator mutably visiting all values associated with the /// entry. /// /// Values are iterated in insertion order. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::default(); /// map.insert("host", "world".parse().unwrap()); /// map.append("host", "earth".parse().unwrap()); /// /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() { /// for e in e.iter_mut() { /// e.set_sensitive(true); /// } /// } /// /// let mut values = map.get_all("host"); /// let mut i = values.iter(); /// assert!(i.next().unwrap().is_sensitive()); /// assert!(i.next().unwrap().is_sensitive()); /// ``` pub fn iter_mut(&mut self) -> ValueIterMut<'_, VE> { ValueIterMut { inner: self.inner.iter_mut(), phantom: PhantomData, } } } impl<'a, VE: ValueEncoding> IntoIterator for OccupiedEntry<'a, VE> where VE: 'a, { type Item = &'a mut MetadataValue; type IntoIter = ValueIterMut<'a, VE>; fn into_iter(self) -> ValueIterMut<'a, VE> { ValueIterMut { inner: self.inner.into_iter(), phantom: PhantomData, } } } impl<'a, 'b: 'a, VE: ValueEncoding> IntoIterator for &'b OccupiedEntry<'a, VE> { type Item = &'a MetadataValue; type IntoIter = ValueIter<'a, VE>; fn into_iter(self) -> ValueIter<'a, VE> { self.iter() } } impl<'a, 'b: 'a, VE: ValueEncoding> IntoIterator for &'b mut OccupiedEntry<'a, VE> { type Item = &'a mut MetadataValue; type IntoIter = ValueIterMut<'a, VE>; fn into_iter(self) -> ValueIterMut<'a, VE> { self.iter_mut() } } // ===== impl GetAll ===== impl<'a, VE: ValueEncoding> GetAll<'a, VE> { /// Returns an iterator visiting all values associated with the entry. /// /// Values are iterated in insertion order. /// /// # Examples /// /// ``` /// # use tonic::metadata::*; /// let mut map = MetadataMap::new(); /// map.insert("x-host", "hello.world".parse().unwrap()); /// map.append("x-host", "hello.earth".parse().unwrap()); /// /// let values = map.get_all("x-host"); /// let mut iter = values.iter(); /// assert_eq!(&"hello.world", iter.next().unwrap()); /// assert_eq!(&"hello.earth", iter.next().unwrap()); /// assert!(iter.next().is_none()); /// ``` pub fn iter(&self) -> ValueIter<'a, VE> { ValueIter { inner: self.inner.as_ref().map(|inner| inner.iter()), phantom: PhantomData, } } } impl<'a, VE: ValueEncoding> PartialEq for GetAll<'a, VE> { fn eq(&self, other: &Self) -> bool { self.inner.iter().eq(other.inner.iter()) } } impl<'a, VE: ValueEncoding> IntoIterator for GetAll<'a, VE> where VE: 'a, { type Item = &'a MetadataValue; type IntoIter = ValueIter<'a, VE>; fn into_iter(self) -> ValueIter<'a, VE> { ValueIter { inner: self.inner.map(|inner| inner.into_iter()), phantom: PhantomData, } } } impl<'a, 'b: 'a, VE: ValueEncoding> IntoIterator for &'b GetAll<'a, VE> { type Item = &'a MetadataValue; type IntoIter = ValueIter<'a, VE>; fn into_iter(self) -> ValueIter<'a, VE> { ValueIter { inner: self.inner.as_ref().map(|inner| inner.into_iter()), phantom: PhantomData, } } } // ===== impl IntoMetadataKey / AsMetadataKey ===== mod into_metadata_key { use super::{MetadataMap, MetadataValue, ValueEncoding}; use crate::metadata::key::MetadataKey; /// A marker trait used to identify values that can be used as insert keys /// to a `MetadataMap`. pub trait IntoMetadataKey: Sealed {} // All methods are on this pub(super) trait, instead of `IntoMetadataKey`, // so that they aren't publicly exposed to the world. // // Being on the `IntoMetadataKey` trait would mean users could call // `"host".insert(&mut map, "localhost")`. // // Ultimately, this allows us to adjust the signatures of these methods // without breaking any external crate. pub trait Sealed { #[doc(hidden)] fn insert(self, map: &mut MetadataMap, val: MetadataValue) -> Option>; #[doc(hidden)] fn append(self, map: &mut MetadataMap, val: MetadataValue) -> bool; } // ==== impls ==== impl Sealed for MetadataKey { #[doc(hidden)] #[inline] fn insert( self, map: &mut MetadataMap, val: MetadataValue, ) -> Option> { map.headers .insert(self.inner, val.inner) .map(MetadataValue::unchecked_from_header_value) } #[doc(hidden)] #[inline] fn append(self, map: &mut MetadataMap, val: MetadataValue) -> bool { map.headers.append(self.inner, val.inner) } } impl IntoMetadataKey for MetadataKey {} impl<'a, VE: ValueEncoding> Sealed for &'a MetadataKey { #[doc(hidden)] #[inline] fn insert( self, map: &mut MetadataMap, val: MetadataValue, ) -> Option> { map.headers .insert(&self.inner, val.inner) .map(MetadataValue::unchecked_from_header_value) } #[doc(hidden)] #[inline] fn append(self, map: &mut MetadataMap, val: MetadataValue) -> bool { map.headers.append(&self.inner, val.inner) } } impl<'a, VE: ValueEncoding> IntoMetadataKey for &'a MetadataKey {} impl Sealed for &'static str { #[doc(hidden)] #[inline] fn insert( self, map: &mut MetadataMap, val: MetadataValue, ) -> Option> { // Perform name validation let key = MetadataKey::::from_static(self); map.headers .insert(key.inner, val.inner) .map(MetadataValue::unchecked_from_header_value) } #[doc(hidden)] #[inline] fn append(self, map: &mut MetadataMap, val: MetadataValue) -> bool { // Perform name validation let key = MetadataKey::::from_static(self); map.headers.append(key.inner, val.inner) } } impl IntoMetadataKey for &'static str {} } mod as_metadata_key { use super::{MetadataMap, MetadataValue, ValueEncoding}; use crate::metadata::key::{InvalidMetadataKey, MetadataKey}; use http::header::{Entry, GetAll, HeaderValue}; /// A marker trait used to identify values that can be used as search keys /// to a `MetadataMap`. pub trait AsMetadataKey: Sealed {} // All methods are on this pub(super) trait, instead of `AsMetadataKey`, // so that they aren't publicly exposed to the world. // // Being on the `AsMetadataKey` trait would mean users could call // `"host".find(&map)`. // // Ultimately, this allows us to adjust the signatures of these methods // without breaking any external crate. pub trait Sealed { #[doc(hidden)] fn get(self, map: &MetadataMap) -> Option<&MetadataValue>; #[doc(hidden)] fn get_mut(self, map: &mut MetadataMap) -> Option<&mut MetadataValue>; #[doc(hidden)] fn get_all(self, map: &MetadataMap) -> Option>; #[doc(hidden)] fn entry(self, map: &mut MetadataMap) -> Result, InvalidMetadataKey>; #[doc(hidden)] fn remove(self, map: &mut MetadataMap) -> Option>; } // ==== impls ==== impl Sealed for MetadataKey { #[doc(hidden)] #[inline] fn get(self, map: &MetadataMap) -> Option<&MetadataValue> { map.headers .get(self.inner) .map(MetadataValue::unchecked_from_header_value_ref) } #[doc(hidden)] #[inline] fn get_mut(self, map: &mut MetadataMap) -> Option<&mut MetadataValue> { map.headers .get_mut(self.inner) .map(MetadataValue::unchecked_from_mut_header_value_ref) } #[doc(hidden)] #[inline] fn get_all(self, map: &MetadataMap) -> Option> { Some(map.headers.get_all(self.inner)) } #[doc(hidden)] #[inline] fn entry( self, map: &mut MetadataMap, ) -> Result, InvalidMetadataKey> { Ok(map.headers.entry(self.inner)) } #[doc(hidden)] #[inline] fn remove(self, map: &mut MetadataMap) -> Option> { map.headers .remove(self.inner) .map(MetadataValue::unchecked_from_header_value) } } impl AsMetadataKey for MetadataKey {} impl<'a, VE: ValueEncoding> Sealed for &'a MetadataKey { #[doc(hidden)] #[inline] fn get(self, map: &MetadataMap) -> Option<&MetadataValue> { map.headers .get(&self.inner) .map(MetadataValue::unchecked_from_header_value_ref) } #[doc(hidden)] #[inline] fn get_mut(self, map: &mut MetadataMap) -> Option<&mut MetadataValue> { map.headers .get_mut(&self.inner) .map(MetadataValue::unchecked_from_mut_header_value_ref) } #[doc(hidden)] #[inline] fn get_all(self, map: &MetadataMap) -> Option> { Some(map.headers.get_all(&self.inner)) } #[doc(hidden)] #[inline] fn entry( self, map: &mut MetadataMap, ) -> Result, InvalidMetadataKey> { Ok(map.headers.entry(&self.inner)) } #[doc(hidden)] #[inline] fn remove(self, map: &mut MetadataMap) -> Option> { map.headers .remove(&self.inner) .map(MetadataValue::unchecked_from_header_value) } } impl<'a, VE: ValueEncoding> AsMetadataKey for &'a MetadataKey {} impl<'a, VE: ValueEncoding> Sealed for &'a str { #[doc(hidden)] #[inline] fn get(self, map: &MetadataMap) -> Option<&MetadataValue> { if !VE::is_valid_key(self) { return None; } map.headers .get(self) .map(MetadataValue::unchecked_from_header_value_ref) } #[doc(hidden)] #[inline] fn get_mut(self, map: &mut MetadataMap) -> Option<&mut MetadataValue> { if !VE::is_valid_key(self) { return None; } map.headers .get_mut(self) .map(MetadataValue::unchecked_from_mut_header_value_ref) } #[doc(hidden)] #[inline] fn get_all(self, map: &MetadataMap) -> Option> { if !VE::is_valid_key(self) { return None; } Some(map.headers.get_all(self)) } #[doc(hidden)] #[inline] fn entry( self, map: &mut MetadataMap, ) -> Result, InvalidMetadataKey> { if !VE::is_valid_key(self) { return Err(InvalidMetadataKey::new()); } let key = http::header::HeaderName::from_bytes(self.as_bytes()) .map_err(|_| InvalidMetadataKey::new())?; let entry = map.headers.entry(key); Ok(entry) } #[doc(hidden)] #[inline] fn remove(self, map: &mut MetadataMap) -> Option> { if !VE::is_valid_key(self) { return None; } map.headers .remove(self) .map(MetadataValue::unchecked_from_header_value) } } impl<'a, VE: ValueEncoding> AsMetadataKey for &'a str {} impl Sealed for String { #[doc(hidden)] #[inline] fn get(self, map: &MetadataMap) -> Option<&MetadataValue> { if !VE::is_valid_key(self.as_str()) { return None; } map.headers .get(self.as_str()) .map(MetadataValue::unchecked_from_header_value_ref) } #[doc(hidden)] #[inline] fn get_mut(self, map: &mut MetadataMap) -> Option<&mut MetadataValue> { if !VE::is_valid_key(self.as_str()) { return None; } map.headers .get_mut(self.as_str()) .map(MetadataValue::unchecked_from_mut_header_value_ref) } #[doc(hidden)] #[inline] fn get_all(self, map: &MetadataMap) -> Option> { if !VE::is_valid_key(self.as_str()) { return None; } Some(map.headers.get_all(self.as_str())) } #[doc(hidden)] #[inline] fn entry( self, map: &mut MetadataMap, ) -> Result, InvalidMetadataKey> { if !VE::is_valid_key(self.as_str()) { return Err(InvalidMetadataKey::new()); } let key = http::header::HeaderName::from_bytes(self.as_bytes()) .map_err(|_| InvalidMetadataKey::new())?; Ok(map.headers.entry(key)) } #[doc(hidden)] #[inline] fn remove(self, map: &mut MetadataMap) -> Option> { if !VE::is_valid_key(self.as_str()) { return None; } map.headers .remove(self.as_str()) .map(MetadataValue::unchecked_from_header_value) } } impl AsMetadataKey for String {} impl<'a, VE: ValueEncoding> Sealed for &'a String { #[doc(hidden)] #[inline] fn get(self, map: &MetadataMap) -> Option<&MetadataValue> { if !VE::is_valid_key(self) { return None; } map.headers .get(self.as_str()) .map(MetadataValue::unchecked_from_header_value_ref) } #[doc(hidden)] #[inline] fn get_mut(self, map: &mut MetadataMap) -> Option<&mut MetadataValue> { if !VE::is_valid_key(self) { return None; } map.headers .get_mut(self.as_str()) .map(MetadataValue::unchecked_from_mut_header_value_ref) } #[doc(hidden)] #[inline] fn get_all(self, map: &MetadataMap) -> Option> { if !VE::is_valid_key(self) { return None; } Some(map.headers.get_all(self.as_str())) } #[doc(hidden)] #[inline] fn entry( self, map: &mut MetadataMap, ) -> Result, InvalidMetadataKey> { if !VE::is_valid_key(self) { return Err(InvalidMetadataKey::new()); } let key = http::header::HeaderName::from_bytes(self.as_bytes()) .map_err(|_| InvalidMetadataKey::new())?; Ok(map.headers.entry(key)) } #[doc(hidden)] #[inline] fn remove(self, map: &mut MetadataMap) -> Option> { if !VE::is_valid_key(self) { return None; } map.headers .remove(self.as_str()) .map(MetadataValue::unchecked_from_header_value) } } impl<'a, VE: ValueEncoding> AsMetadataKey for &'a String {} } mod as_encoding_agnostic_metadata_key { use super::{MetadataMap, ValueEncoding}; use crate::metadata::key::MetadataKey; /// A marker trait used to identify values that can be used as search keys /// to a `MetadataMap`, for operations that don't expose the actual value. pub trait AsEncodingAgnosticMetadataKey: Sealed {} // All methods are on this pub(super) trait, instead of // `AsEncodingAgnosticMetadataKey`, so that they aren't publicly exposed to // the world. // // Being on the `AsEncodingAgnosticMetadataKey` trait would mean users could // call `"host".contains_key(&map)`. // // Ultimately, this allows us to adjust the signatures of these methods // without breaking any external crate. pub trait Sealed { #[doc(hidden)] fn contains_key(&self, map: &MetadataMap) -> bool; } // ==== impls ==== impl Sealed for MetadataKey { #[doc(hidden)] #[inline] fn contains_key(&self, map: &MetadataMap) -> bool { map.headers.contains_key(&self.inner) } } impl AsEncodingAgnosticMetadataKey for MetadataKey {} impl<'a, VE: ValueEncoding> Sealed for &'a MetadataKey { #[doc(hidden)] #[inline] fn contains_key(&self, map: &MetadataMap) -> bool { map.headers.contains_key(&self.inner) } } impl<'a, VE: ValueEncoding> AsEncodingAgnosticMetadataKey for &'a MetadataKey {} impl<'a> Sealed for &'a str { #[doc(hidden)] #[inline] fn contains_key(&self, map: &MetadataMap) -> bool { map.headers.contains_key(*self) } } impl<'a> AsEncodingAgnosticMetadataKey for &'a str {} impl Sealed for String { #[doc(hidden)] #[inline] fn contains_key(&self, map: &MetadataMap) -> bool { map.headers.contains_key(self.as_str()) } } impl AsEncodingAgnosticMetadataKey for String {} impl<'a> Sealed for &'a String { #[doc(hidden)] #[inline] fn contains_key(&self, map: &MetadataMap) -> bool { map.headers.contains_key(self.as_str()) } } impl<'a> AsEncodingAgnosticMetadataKey for &'a String {} } #[cfg(test)] mod tests { use super::*; #[test] fn test_from_headers_takes_http_headers() { let mut http_map = http::HeaderMap::new(); http_map.insert("x-host", "example.com".parse().unwrap()); let map = MetadataMap::from_headers(http_map); assert_eq!(map.get("x-host").unwrap(), "example.com"); } #[test] fn test_to_headers_encoding() { use crate::Code; use crate::Status; let special_char_message = "Beyond ascii \t\n\ršŸŒ¶ļøšŸ’‰šŸ’§šŸ®šŸŗ"; let s1 = Status::new(Code::Unknown, special_char_message); assert_eq!(s1.message(), special_char_message); let s1_map = s1.to_header_map().unwrap(); let s2 = Status::from_header_map(&s1_map).unwrap(); assert_eq!(s1.message(), s2.message()); } #[test] fn test_iter_categorizes_ascii_entries() { let mut map = MetadataMap::new(); map.insert("x-word", "hello".parse().unwrap()); map.append_bin("x-word-bin", MetadataValue::from_bytes(b"goodbye")); map.insert_bin("x-number-bin", MetadataValue::from_bytes(b"123")); let mut found_x_word = false; for key_and_value in map.iter() { if let KeyAndValueRef::Ascii(key, _value) = key_and_value { if key.as_str() == "x-word" { found_x_word = true; } else { panic!("Unexpected key"); } } } assert!(found_x_word); } #[test] fn test_iter_categorizes_binary_entries() { let mut map = MetadataMap::new(); map.insert("x-word", "hello".parse().unwrap()); map.append_bin("x-word-bin", MetadataValue::from_bytes(b"goodbye")); let mut found_x_word_bin = false; for key_and_value in map.iter() { if let KeyAndValueRef::Binary(key, _value) = key_and_value { if key.as_str() == "x-word-bin" { found_x_word_bin = true; } else { panic!("Unexpected key"); } } } assert!(found_x_word_bin); } #[test] fn test_iter_mut_categorizes_ascii_entries() { let mut map = MetadataMap::new(); map.insert("x-word", "hello".parse().unwrap()); map.append_bin("x-word-bin", MetadataValue::from_bytes(b"goodbye")); map.insert_bin("x-number-bin", MetadataValue::from_bytes(b"123")); let mut found_x_word = false; for key_and_value in map.iter_mut() { if let KeyAndMutValueRef::Ascii(key, _value) = key_and_value { if key.as_str() == "x-word" { found_x_word = true; } else { panic!("Unexpected key"); } } } assert!(found_x_word); } #[test] fn test_iter_mut_categorizes_binary_entries() { let mut map = MetadataMap::new(); map.insert("x-word", "hello".parse().unwrap()); map.append_bin("x-word-bin", MetadataValue::from_bytes(b"goodbye")); let mut found_x_word_bin = false; for key_and_value in map.iter_mut() { if let KeyAndMutValueRef::Binary(key, _value) = key_and_value { if key.as_str() == "x-word-bin" { found_x_word_bin = true; } else { panic!("Unexpected key"); } } } assert!(found_x_word_bin); } #[test] fn test_keys_categorizes_ascii_entries() { let mut map = MetadataMap::new(); map.insert("x-word", "hello".parse().unwrap()); map.append_bin("x-word-bin", MetadataValue::from_bytes(b"goodbye")); map.insert_bin("x-number-bin", MetadataValue::from_bytes(b"123")); let mut found_x_word = false; for key in map.keys() { if let KeyRef::Ascii(key) = key { if key.as_str() == "x-word" { found_x_word = true; } else { panic!("Unexpected key"); } } } assert!(found_x_word); } #[test] fn test_keys_categorizes_binary_entries() { let mut map = MetadataMap::new(); map.insert("x-word", "hello".parse().unwrap()); map.insert_bin("x-number-bin", MetadataValue::from_bytes(b"123")); let mut found_x_number_bin = false; for key in map.keys() { if let KeyRef::Binary(key) = key { if key.as_str() == "x-number-bin" { found_x_number_bin = true; } else { panic!("Unexpected key"); } } } assert!(found_x_number_bin); } #[test] fn test_values_categorizes_ascii_entries() { let mut map = MetadataMap::new(); map.insert("x-word", "hello".parse().unwrap()); map.append_bin("x-word-bin", MetadataValue::from_bytes(b"goodbye")); map.insert_bin("x-number-bin", MetadataValue::from_bytes(b"123")); let mut found_x_word = false; for value in map.values() { if let ValueRef::Ascii(value) = value { if *value == "hello" { found_x_word = true; } else { panic!("Unexpected key"); } } } assert!(found_x_word); } #[test] fn test_values_categorizes_binary_entries() { let mut map = MetadataMap::new(); map.insert("x-word", "hello".parse().unwrap()); map.append_bin("x-word-bin", MetadataValue::from_bytes(b"goodbye")); let mut found_x_word_bin = false; for value_ref in map.values() { if let ValueRef::Binary(value) = value_ref { assert_eq!(*value, "goodbye"); found_x_word_bin = true; } } assert!(found_x_word_bin); } #[test] fn test_values_mut_categorizes_ascii_entries() { let mut map = MetadataMap::new(); map.insert("x-word", "hello".parse().unwrap()); map.append_bin("x-word-bin", MetadataValue::from_bytes(b"goodbye")); map.insert_bin("x-number-bin", MetadataValue::from_bytes(b"123")); let mut found_x_word = false; for value_ref in map.values_mut() { if let ValueRefMut::Ascii(value) = value_ref { assert_eq!(*value, "hello"); found_x_word = true; } } assert!(found_x_word); } #[test] fn test_values_mut_categorizes_binary_entries() { let mut map = MetadataMap::new(); map.insert("x-word", "hello".parse().unwrap()); map.append_bin("x-word-bin", MetadataValue::from_bytes(b"goodbye")); let mut found_x_word_bin = false; for value in map.values_mut() { if let ValueRefMut::Binary(value) = value { assert_eq!(*value, "goodbye"); found_x_word_bin = true; } } assert!(found_x_word_bin); } #[allow(dead_code)] fn value_drain_is_send_sync() { fn is_send_sync() {} is_send_sync::>(); is_send_sync::>(); is_send_sync::>(); is_send_sync::>(); is_send_sync::>(); is_send_sync::>(); } }