| 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<Ascii>, &'a MetadataValue<Ascii>), |
| /// A binary metadata key and value. |
| Binary(&'a MetadataKey<Binary>, &'a MetadataValue<Binary>), |
| } |
| |
| /// 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<Ascii>, &'a mut MetadataValue<Ascii>), |
| /// A binary metadata key and value. |
| Binary(&'a MetadataKey<Binary>, &'a mut MetadataValue<Binary>), |
| } |
| |
| /// `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<VE>, |
| } |
| |
| /// 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<Ascii>), |
| /// A binary metadata key and value. |
| Binary(&'a MetadataKey<Binary>), |
| } |
| |
| /// `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<Ascii>), |
| /// A binary metadata key and value. |
| Binary(&'a MetadataValue<Binary>), |
| } |
| |
| /// `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<Ascii>), |
| /// A binary metadata key and value. |
| Binary(&'a mut MetadataValue<Binary>), |
| } |
| |
| /// An iterator of all values associated with a single metadata key. |
| #[derive(Debug)] |
| pub struct ValueIter<'a, VE: ValueEncoding> { |
| inner: Option<http::header::ValueIter<'a, http::header::HeaderValue>>, |
| phantom: PhantomData<VE>, |
| } |
| |
| /// 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<VE>, |
| } |
| |
| /// 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<http::header::GetAll<'a, http::header::HeaderValue>>, |
| phantom: PhantomData<VE>, |
| } |
| |
| /// 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<VE>, |
| } |
| |
| /// 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<VE>, |
| } |
| |
| 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<K>(&self, key: K) -> Option<&MetadataValue<Ascii>> |
| where |
| K: AsMetadataKey<Ascii>, |
| { |
| 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<K>(&self, key: K) -> Option<&MetadataValue<Binary>> |
| where |
| K: AsMetadataKey<Binary>, |
| { |
| 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<K>(&mut self, key: K) -> Option<&mut MetadataValue<Ascii>> |
| where |
| K: AsMetadataKey<Ascii>, |
| { |
| 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<K>(&mut self, key: K) -> Option<&mut MetadataValue<Binary>> |
| where |
| K: AsMetadataKey<Binary>, |
| { |
| 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<K>(&self, key: K) -> GetAll<'_, Ascii> |
| where |
| K: AsMetadataKey<Ascii>, |
| { |
| 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<K>(&self, key: K) -> GetAll<'_, Binary> |
| where |
| K: AsMetadataKey<Binary>, |
| { |
| 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<K>(&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<K>(&mut self, key: K) -> Result<Entry<'_, Ascii>, InvalidMetadataKey> |
| where |
| K: AsMetadataKey<Ascii>, |
| { |
| self.generic_entry::<Ascii, K>(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<K>(&mut self, key: K) -> Result<Entry<'_, Binary>, InvalidMetadataKey> |
| where |
| K: AsMetadataKey<Binary>, |
| { |
| self.generic_entry::<Binary, K>(key) |
| } |
| |
| fn generic_entry<VE: ValueEncoding, K>( |
| &mut self, |
| key: K, |
| ) -> Result<Entry<'_, VE>, InvalidMetadataKey> |
| where |
| K: AsMetadataKey<VE>, |
| { |
| 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<Ascii>`. |
| /// |
| /// 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<K>(&mut self, key: K, val: MetadataValue<Ascii>) -> Option<MetadataValue<Ascii>> |
| where |
| K: IntoMetadataKey<Ascii>, |
| { |
| 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<Binary>`. |
| /// |
| /// # 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<K>( |
| &mut self, |
| key: K, |
| val: MetadataValue<Binary>, |
| ) -> Option<MetadataValue<Binary>> |
| where |
| K: IntoMetadataKey<Binary>, |
| { |
| 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<Ascii>`. |
| /// |
| /// 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<K>(&mut self, key: K, value: MetadataValue<Ascii>) -> bool |
| where |
| K: IntoMetadataKey<Ascii>, |
| { |
| 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<Binary>`. |
| /// |
| /// # 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<K>(&mut self, key: K, value: MetadataValue<Binary>) -> bool |
| where |
| K: IntoMetadataKey<Binary>, |
| { |
| 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<K>(&mut self, key: K) -> Option<MetadataValue<Ascii>> |
| where |
| K: AsMetadataKey<Ascii>, |
| { |
| 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<K>(&mut self, key: K) -> Option<MetadataValue<Binary>> |
| where |
| K: AsMetadataKey<Binary>, |
| { |
| 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::Item> { |
| 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<usize>) { |
| self.inner.size_hint() |
| } |
| } |
| |
| // ===== impl IterMut ===== |
| |
| impl<'a> Iterator for IterMut<'a> { |
| type Item = KeyAndMutValueRef<'a>; |
| |
| fn next(&mut self) -> Option<Self::Item> { |
| 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<usize>) { |
| self.inner.size_hint() |
| } |
| } |
| |
| // ===== impl ValueDrain ===== |
| |
| impl<'a, VE: ValueEncoding> Iterator for ValueDrain<'a, VE> { |
| type Item = MetadataValue<VE>; |
| |
| fn next(&mut self) -> Option<Self::Item> { |
| self.inner |
| .next() |
| .map(MetadataValue::unchecked_from_header_value) |
| } |
| |
| fn size_hint(&self) -> (usize, Option<usize>) { |
| self.inner.size_hint() |
| } |
| } |
| |
| // ===== impl Keys ===== |
| |
| impl<'a> Iterator for Keys<'a> { |
| type Item = KeyRef<'a>; |
| |
| fn next(&mut self) -> Option<Self::Item> { |
| 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<usize>) { |
| 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::Item> { |
| 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<usize>) { |
| self.inner.size_hint() |
| } |
| } |
| |
| // ===== impl Values ==== |
| |
| impl<'a> Iterator for ValuesMut<'a> { |
| type Item = ValueRefMut<'a>; |
| |
| fn next(&mut self) -> Option<Self::Item> { |
| 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<usize>) { |
| self.inner.size_hint() |
| } |
| } |
| |
| // ===== impl ValueIter ===== |
| |
| impl<'a, VE: ValueEncoding> Iterator for ValueIter<'a, VE> |
| where |
| VE: 'a, |
| { |
| type Item = &'a MetadataValue<VE>; |
| |
| fn next(&mut self) -> Option<Self::Item> { |
| match self.inner { |
| Some(ref mut inner) => inner |
| .next() |
| .map(MetadataValue::unchecked_from_header_value_ref), |
| None => None, |
| } |
| } |
| |
| fn size_hint(&self) -> (usize, Option<usize>) { |
| 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<Self::Item> { |
| 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<VE>; |
| |
| fn next(&mut self) -> Option<Self::Item> { |
| 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::Item> { |
| 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<VE>) -> &'a mut MetadataValue<VE> { |
| 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<F: FnOnce() -> MetadataValue<VE>>( |
| self, |
| default: F, |
| ) -> &'a mut MetadataValue<VE> { |
| 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<VE> { |
| 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<VE> { |
| 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<VE> { |
| 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<VE>) -> &'a mut MetadataValue<VE> { |
| 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<VE>) -> 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<VE> { |
| 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<VE> { |
| 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<VE> { |
| 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<VE> { |
| 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<VE>) -> MetadataValue<VE> { |
| 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<VE>) -> 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<VE>) { |
| 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<VE> { |
| 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<VE>, MetadataValue<VE>) { |
| 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<VE>, 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<VE>; |
| 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<VE>; |
| 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<VE>; |
| 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<VE>; |
| 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<VE>; |
| 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<VE: ValueEncoding>: Sealed<VE> {} |
| |
| // 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<VE: ValueEncoding> { |
| #[doc(hidden)] |
| fn insert(self, map: &mut MetadataMap, val: MetadataValue<VE>) |
| -> Option<MetadataValue<VE>>; |
| |
| #[doc(hidden)] |
| fn append(self, map: &mut MetadataMap, val: MetadataValue<VE>) -> bool; |
| } |
| |
| // ==== impls ==== |
| |
| impl<VE: ValueEncoding> Sealed<VE> for MetadataKey<VE> { |
| #[doc(hidden)] |
| #[inline] |
| fn insert( |
| self, |
| map: &mut MetadataMap, |
| val: MetadataValue<VE>, |
| ) -> Option<MetadataValue<VE>> { |
| map.headers |
| .insert(self.inner, val.inner) |
| .map(MetadataValue::unchecked_from_header_value) |
| } |
| |
| #[doc(hidden)] |
| #[inline] |
| fn append(self, map: &mut MetadataMap, val: MetadataValue<VE>) -> bool { |
| map.headers.append(self.inner, val.inner) |
| } |
| } |
| |
| impl<VE: ValueEncoding> IntoMetadataKey<VE> for MetadataKey<VE> {} |
| |
| impl<'a, VE: ValueEncoding> Sealed<VE> for &'a MetadataKey<VE> { |
| #[doc(hidden)] |
| #[inline] |
| fn insert( |
| self, |
| map: &mut MetadataMap, |
| val: MetadataValue<VE>, |
| ) -> Option<MetadataValue<VE>> { |
| map.headers |
| .insert(&self.inner, val.inner) |
| .map(MetadataValue::unchecked_from_header_value) |
| } |
| #[doc(hidden)] |
| #[inline] |
| fn append(self, map: &mut MetadataMap, val: MetadataValue<VE>) -> bool { |
| map.headers.append(&self.inner, val.inner) |
| } |
| } |
| |
| impl<'a, VE: ValueEncoding> IntoMetadataKey<VE> for &'a MetadataKey<VE> {} |
| |
| impl<VE: ValueEncoding> Sealed<VE> for &'static str { |
| #[doc(hidden)] |
| #[inline] |
| fn insert( |
| self, |
| map: &mut MetadataMap, |
| val: MetadataValue<VE>, |
| ) -> Option<MetadataValue<VE>> { |
| // Perform name validation |
| let key = MetadataKey::<VE>::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<VE>) -> bool { |
| // Perform name validation |
| let key = MetadataKey::<VE>::from_static(self); |
| |
| map.headers.append(key.inner, val.inner) |
| } |
| } |
| |
| impl<VE: ValueEncoding> IntoMetadataKey<VE> 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<VE: ValueEncoding>: Sealed<VE> {} |
| |
| // 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<VE: ValueEncoding> { |
| #[doc(hidden)] |
| fn get(self, map: &MetadataMap) -> Option<&MetadataValue<VE>>; |
| |
| #[doc(hidden)] |
| fn get_mut(self, map: &mut MetadataMap) -> Option<&mut MetadataValue<VE>>; |
| |
| #[doc(hidden)] |
| fn get_all(self, map: &MetadataMap) -> Option<GetAll<'_, HeaderValue>>; |
| |
| #[doc(hidden)] |
| fn entry(self, map: &mut MetadataMap) |
| -> Result<Entry<'_, HeaderValue>, InvalidMetadataKey>; |
| |
| #[doc(hidden)] |
| fn remove(self, map: &mut MetadataMap) -> Option<MetadataValue<VE>>; |
| } |
| |
| // ==== impls ==== |
| |
| impl<VE: ValueEncoding> Sealed<VE> for MetadataKey<VE> { |
| #[doc(hidden)] |
| #[inline] |
| fn get(self, map: &MetadataMap) -> Option<&MetadataValue<VE>> { |
| 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<VE>> { |
| map.headers |
| .get_mut(self.inner) |
| .map(MetadataValue::unchecked_from_mut_header_value_ref) |
| } |
| |
| #[doc(hidden)] |
| #[inline] |
| fn get_all(self, map: &MetadataMap) -> Option<GetAll<'_, HeaderValue>> { |
| Some(map.headers.get_all(self.inner)) |
| } |
| |
| #[doc(hidden)] |
| #[inline] |
| fn entry( |
| self, |
| map: &mut MetadataMap, |
| ) -> Result<Entry<'_, HeaderValue>, InvalidMetadataKey> { |
| Ok(map.headers.entry(self.inner)) |
| } |
| |
| #[doc(hidden)] |
| #[inline] |
| fn remove(self, map: &mut MetadataMap) -> Option<MetadataValue<VE>> { |
| map.headers |
| .remove(self.inner) |
| .map(MetadataValue::unchecked_from_header_value) |
| } |
| } |
| |
| impl<VE: ValueEncoding> AsMetadataKey<VE> for MetadataKey<VE> {} |
| |
| impl<'a, VE: ValueEncoding> Sealed<VE> for &'a MetadataKey<VE> { |
| #[doc(hidden)] |
| #[inline] |
| fn get(self, map: &MetadataMap) -> Option<&MetadataValue<VE>> { |
| 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<VE>> { |
| map.headers |
| .get_mut(&self.inner) |
| .map(MetadataValue::unchecked_from_mut_header_value_ref) |
| } |
| |
| #[doc(hidden)] |
| #[inline] |
| fn get_all(self, map: &MetadataMap) -> Option<GetAll<'_, HeaderValue>> { |
| Some(map.headers.get_all(&self.inner)) |
| } |
| |
| #[doc(hidden)] |
| #[inline] |
| fn entry( |
| self, |
| map: &mut MetadataMap, |
| ) -> Result<Entry<'_, HeaderValue>, InvalidMetadataKey> { |
| Ok(map.headers.entry(&self.inner)) |
| } |
| |
| #[doc(hidden)] |
| #[inline] |
| fn remove(self, map: &mut MetadataMap) -> Option<MetadataValue<VE>> { |
| map.headers |
| .remove(&self.inner) |
| .map(MetadataValue::unchecked_from_header_value) |
| } |
| } |
| |
| impl<'a, VE: ValueEncoding> AsMetadataKey<VE> for &'a MetadataKey<VE> {} |
| |
| impl<'a, VE: ValueEncoding> Sealed<VE> for &'a str { |
| #[doc(hidden)] |
| #[inline] |
| fn get(self, map: &MetadataMap) -> Option<&MetadataValue<VE>> { |
| 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<VE>> { |
| 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<GetAll<'_, HeaderValue>> { |
| if !VE::is_valid_key(self) { |
| return None; |
| } |
| Some(map.headers.get_all(self)) |
| } |
| |
| #[doc(hidden)] |
| #[inline] |
| fn entry( |
| self, |
| map: &mut MetadataMap, |
| ) -> Result<Entry<'_, HeaderValue>, 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<MetadataValue<VE>> { |
| if !VE::is_valid_key(self) { |
| return None; |
| } |
| map.headers |
| .remove(self) |
| .map(MetadataValue::unchecked_from_header_value) |
| } |
| } |
| |
| impl<'a, VE: ValueEncoding> AsMetadataKey<VE> for &'a str {} |
| |
| impl<VE: ValueEncoding> Sealed<VE> for String { |
| #[doc(hidden)] |
| #[inline] |
| fn get(self, map: &MetadataMap) -> Option<&MetadataValue<VE>> { |
| 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<VE>> { |
| 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<GetAll<'_, HeaderValue>> { |
| 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<Entry<'_, HeaderValue>, 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<MetadataValue<VE>> { |
| if !VE::is_valid_key(self.as_str()) { |
| return None; |
| } |
| map.headers |
| .remove(self.as_str()) |
| .map(MetadataValue::unchecked_from_header_value) |
| } |
| } |
| |
| impl<VE: ValueEncoding> AsMetadataKey<VE> for String {} |
| |
| impl<'a, VE: ValueEncoding> Sealed<VE> for &'a String { |
| #[doc(hidden)] |
| #[inline] |
| fn get(self, map: &MetadataMap) -> Option<&MetadataValue<VE>> { |
| 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<VE>> { |
| 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<GetAll<'_, HeaderValue>> { |
| 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<Entry<'_, HeaderValue>, 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<MetadataValue<VE>> { |
| 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<VE> 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<VE: ValueEncoding> Sealed for MetadataKey<VE> { |
| #[doc(hidden)] |
| #[inline] |
| fn contains_key(&self, map: &MetadataMap) -> bool { |
| map.headers.contains_key(&self.inner) |
| } |
| } |
| |
| impl<VE: ValueEncoding> AsEncodingAgnosticMetadataKey for MetadataKey<VE> {} |
| |
| impl<'a, VE: ValueEncoding> Sealed for &'a MetadataKey<VE> { |
| #[doc(hidden)] |
| #[inline] |
| fn contains_key(&self, map: &MetadataMap) -> bool { |
| map.headers.contains_key(&self.inner) |
| } |
| } |
| |
| impl<'a, VE: ValueEncoding> AsEncodingAgnosticMetadataKey for &'a MetadataKey<VE> {} |
| |
| 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<T: Send + Sync>() {} |
| |
| is_send_sync::<Iter<'_>>(); |
| is_send_sync::<IterMut<'_>>(); |
| |
| is_send_sync::<ValueDrain<'_, Ascii>>(); |
| is_send_sync::<ValueDrain<'_, Binary>>(); |
| |
| is_send_sync::<ValueIterMut<'_, Ascii>>(); |
| is_send_sync::<ValueIterMut<'_, Binary>>(); |
| } |
| } |