use std::{
borrow::{Borrow, Cow},
fmt, ops,
str::FromStr,
};
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use serde_with::{DeserializeFromStr, SerializeDisplay};
use crate::{IsEmpty, Value};
pub const FROM: HeaderName = HeaderName::from_static("from");
pub const TO: HeaderName = HeaderName::from_static("to");
pub const CREATED: HeaderName = HeaderName::from_static("created");
pub const REQUEST_ID: HeaderName = HeaderName::from_static("request_id");
#[derive(Clone, PartialEq, Eq, Hash, DeserializeFromStr, SerializeDisplay)]
pub struct HeaderName {
inner: Cow<'static, str>,
}
impl HeaderName {
pub const fn from_static(s: &'static str) -> Self {
HeaderName {
inner: Cow::Borrowed(s),
}
}
}
impl fmt::Debug for HeaderName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "HeaderName({})", self.inner)
}
}
impl fmt::Display for HeaderName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.inner)
}
}
impl FromStr for HeaderName {
type Err = ParseHeaderNameError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(HeaderName {
inner: Cow::Owned(s.to_string()),
})
}
}
impl PartialEq<String> for HeaderName {
fn eq(&self, other: &String) -> bool {
&self.inner == other
}
}
impl PartialEq<str> for HeaderName {
fn eq(&self, other: &str) -> bool {
self.inner == other
}
}
impl Borrow<str> for HeaderName {
fn borrow(&self) -> &str {
&self.inner
}
}
mod into_header_name {
use indexmap::IndexMap;
use serde::Serialize;
use crate::Value;
use super::HeaderName;
pub trait IntoHeaderName: Sealed {}
impl<T: Sealed> IntoHeaderName for T {}
pub trait Sealed: Sized {
fn insert<V>(self, map: &mut IndexMap<HeaderName, V>, value: V);
fn try_insert_typed<V: Value, TV: Serialize>(
self,
map: &mut IndexMap<HeaderName, V>,
value: TV,
) -> Result<(), V::Error> {
self.insert(map, V::from_typed(&value)?);
Ok(())
}
}
impl Sealed for HeaderName {
fn insert<V>(self, map: &mut IndexMap<HeaderName, V>, value: V) {
map.insert(self, value);
}
}
impl Sealed for &HeaderName {
fn insert<V>(self, map: &mut IndexMap<HeaderName, V>, value: V) {
map.insert(self.clone(), value);
}
}
impl Sealed for String {
fn insert<V>(self, map: &mut IndexMap<HeaderName, V>, value: V) {
map.insert(self.parse().expect("valid header name"), value);
}
}
impl Sealed for &str {
fn insert<V>(self, map: &mut IndexMap<HeaderName, V>, value: V) {
map.insert(self.parse().expect("valid header name"), value);
}
}
}
pub use into_header_name::IntoHeaderName;
mod as_header_name {
use indexmap::IndexMap;
pub trait AsHeaderName: Sealed {}
impl<T: Sealed> AsHeaderName for T {}
pub trait Sealed {
fn get_from_map<'map, V>(
&self,
map: &'map IndexMap<super::HeaderName, V>,
) -> Option<&'map V>;
}
impl Sealed for super::HeaderName {
fn get_from_map<'map, V>(
&self,
map: &'map IndexMap<super::HeaderName, V>,
) -> Option<&'map V> {
map.get(self)
}
}
impl Sealed for &super::HeaderName {
fn get_from_map<'map, V>(
&self,
map: &'map IndexMap<super::HeaderName, V>,
) -> Option<&'map V> {
map.get(*self)
}
}
impl Sealed for &str {
fn get_from_map<'map, V>(
&self,
map: &'map IndexMap<super::HeaderName, V>,
) -> Option<&'map V> {
map.get(*self)
}
}
impl Sealed for String {
fn get_from_map<'map, V>(
&self,
map: &'map IndexMap<super::HeaderName, V>,
) -> Option<&'map V> {
map.get(self.as_str())
}
}
}
pub use as_header_name::AsHeaderName;
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct ParseHeaderNameError {}
impl fmt::Display for ParseHeaderNameError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "malformed header name")
}
}
impl std::error::Error for ParseHeaderNameError {}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Headers<V> {
#[serde(flatten)]
values: IndexMap<HeaderName, V>,
}
impl<V> Headers<V> {
pub fn len(&self) -> usize {
self.values.len()
}
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
pub fn get(&self, name: impl AsHeaderName) -> Option<&V> {
name.get_from_map(&self.values)
}
pub fn contains(&self, name: impl AsHeaderName) -> bool {
name.get_from_map(&self.values).is_some()
}
pub fn insert(&mut self, name: impl IntoHeaderName, value: V) {
name.insert(&mut self.values, value);
}
pub fn iter(&self) -> impl Iterator<Item = (&HeaderName, &V)> {
self.values.iter()
}
}
impl<V: Value> Headers<V> {
pub fn try_get<'de, T: Deserialize<'de>>(
&'de self,
name: impl AsHeaderName,
) -> Option<Result<T, V::Error>> {
name.get_from_map(&self.values).map(|v| V::to_typed(v))
}
pub fn try_insert_value(
&mut self,
name: impl IntoHeaderName,
value: impl Serialize,
) -> Result<(), V::Error> {
name.try_insert_typed(&mut self.values, value)
}
}
impl<V> IsEmpty for Headers<V> {
fn is_empty(&self) -> bool {
self.values.is_empty()
}
}
impl<K: AsHeaderName, V> ops::Index<K> for Headers<V> {
type Output = V;
fn index(&self, index: K) -> &Self::Output {
self.get(index).expect("no entry found for header name")
}
}
impl<'a, V> IntoIterator for &'a Headers<V> {
type Item = (&'a HeaderName, &'a V);
type IntoIter = indexmap::map::Iter<'a, HeaderName, V>;
fn into_iter(self) -> Self::IntoIter {
self.values.iter()
}
}
impl<V> IntoIterator for Headers<V> {
type Item = (HeaderName, V);
type IntoIter = indexmap::map::IntoIter<HeaderName, V>;
fn into_iter(self) -> Self::IntoIter {
self.values.into_iter()
}
}
impl<V> FromIterator<(HeaderName, V)> for Headers<V> {
fn from_iter<T: IntoIterator<Item = (HeaderName, V)>>(iter: T) -> Self {
Headers {
values: iter.into_iter().collect(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn insert_static_str() {
let mut headers = Headers::default();
headers.insert("demo", "application/json");
assert_eq!(headers.len(), 1);
assert!(headers.contains("demo"));
}
#[test]
fn insert_const() {
let mut headers = Headers::default();
headers.insert(TO, "application/json");
assert_eq!(headers.len(), 1);
assert!(headers.contains(TO));
}
}