use std::str::FromStr;
use hyper::header::HeaderName;
use poem::http::{HeaderMap, HeaderValue};
#[derive(Debug, Clone, Default)]
pub struct Metadata {
pub(crate) headers: HeaderMap,
}
impl Metadata {
#[inline]
pub fn new() -> Self {
Self {
headers: Default::default(),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
headers: HeaderMap::with_capacity(capacity),
}
}
#[inline]
pub fn len(&self) -> usize {
self.headers.len()
}
#[inline]
pub fn keys_len(&self) -> usize {
self.headers.keys_len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.headers.is_empty()
}
#[inline]
pub fn clear(&mut self) {
self.headers.clear();
}
#[inline]
pub fn capacity(&self) -> usize {
self.headers.capacity()
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.headers.reserve(additional);
}
pub fn get(&self, key: impl AsRef<str>) -> Option<&str> {
self.headers
.get(key.as_ref())
.and_then(|value| value.to_str().ok())
}
pub fn get_bin(&self, key: impl AsRef<str>) -> Option<Vec<u8>> {
self.headers
.get(format!("{}-bin", key.as_ref()))
.and_then(|value| base64::decode_config(value.as_bytes(), base64::STANDARD_NO_PAD).ok())
}
#[inline]
pub fn get_all(&self, key: impl AsRef<str>) -> GetAll<'_> {
GetAll {
iter: self.headers.get_all(key.as_ref()).into_iter(),
}
}
#[inline]
pub fn get_bin_all(&self, key: impl AsRef<str>) -> GetBinaryAll<'_> {
GetBinaryAll {
iter: self
.headers
.get_all(format!("{}-bin", key.as_ref()))
.into_iter(),
}
}
#[inline]
pub fn contains_key(&self, key: impl AsRef<str>) -> bool {
self.headers.contains_key(key.as_ref())
}
#[inline]
pub fn contains_bin_key(&self, key: impl AsRef<str>) -> bool {
self.headers.contains_key(format!("{}-bin", key.as_ref()))
}
pub fn append(&mut self, key: impl AsRef<str>, value: impl Into<String>) {
self.headers.append(
HeaderName::from_str(key.as_ref()).expect("valid name"),
HeaderValue::from_maybe_shared(value.into()).expect("valid value"),
);
}
pub fn append_bin(&mut self, key: impl AsRef<str>, value: impl AsRef<[u8]>) {
self.headers.append(
HeaderName::from_str(&format!("{}-bin", key.as_ref())).expect("valid name"),
HeaderValue::from_maybe_shared(base64::encode_config(value, base64::STANDARD_NO_PAD))
.expect("valid value"),
);
}
pub fn insert(&mut self, key: impl AsRef<str>, value: impl Into<String>) {
self.headers.insert(
HeaderName::from_str(key.as_ref()).expect("valid name"),
HeaderValue::from_maybe_shared(value.into()).expect("valid value"),
);
}
pub fn insert_bin(&mut self, key: impl AsRef<str>, value: impl AsRef<[u8]>) {
self.headers.insert(
HeaderName::from_str(&format!("{}-bin", key.as_ref())).expect("valid name"),
HeaderValue::from_maybe_shared(base64::encode_config(value, base64::STANDARD_NO_PAD))
.expect("valid value"),
);
}
}
pub struct GetAll<'a> {
iter: poem::http::header::ValueIter<'a, HeaderValue>,
}
impl<'a> Iterator for GetAll<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
for value in &mut self.iter {
if let Ok(value) = value.to_str() {
return Some(value);
}
}
None
}
}
pub struct GetBinaryAll<'a> {
iter: poem::http::header::ValueIter<'a, HeaderValue>,
}
impl<'a> Iterator for GetBinaryAll<'a> {
type Item = Vec<u8>;
fn next(&mut self) -> Option<Self::Item> {
for value in &mut self.iter {
if let Ok(value) = base64::decode_config(value.as_bytes(), base64::STANDARD_NO_PAD) {
return Some(value);
}
}
None
}
}