use crate::{error::Error, Result};
use std::{
iter::{FromIterator, Map},
result::Result as StdResult,
str::FromStr,
};
use edgeworker_sys::Headers as EdgeHeaders;
use http::{header::HeaderName, HeaderMap, HeaderValue};
use js_sys::Array;
use wasm_bindgen::JsValue;
pub struct Headers(pub EdgeHeaders);
impl std::fmt::Debug for Headers {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Headers {\n")?;
for (k, v) in self.entries() {
f.write_str(&format!("{} = {}\n", k, v))?;
}
f.write_str("}\n")
}
}
#[allow(clippy::new_without_default)]
impl Headers {
pub fn new() -> Self {
Headers(EdgeHeaders::new().unwrap())
}
pub fn get(&self, name: &str) -> Result<Option<String>> {
self.0.get(name).map_err(Error::from)
}
pub fn has(&self, name: &str) -> Result<bool> {
self.0.has(name).map_err(Error::from)
}
pub fn append(&mut self, name: &str, value: &str) -> Result<()> {
self.0.append(name, value).map_err(Error::from)
}
pub fn set(&mut self, name: &str, value: &str) -> Result<()> {
self.0.set(name, value).map_err(Error::from)
}
pub fn delete(&mut self, name: &str) -> Result<()> {
self.0.delete(name).map_err(Error::from)
}
pub fn entries(&self) -> HeaderIterator {
self.0
.entries()
.unwrap()
.into_iter()
.map((|a| a.unwrap().into()) as F1)
.map(|a: Array| (a.get(0).as_string().unwrap(), a.get(1).as_string().unwrap()))
}
pub fn keys(&self) -> impl Iterator<Item = String> {
self.0
.keys()
.unwrap()
.into_iter()
.map(|a| a.unwrap().as_string().unwrap())
}
pub fn values(&self) -> impl Iterator<Item = String> {
self.0
.values()
.unwrap()
.into_iter()
.map(|a| a.unwrap().as_string().unwrap())
}
}
type F1 = fn(StdResult<JsValue, JsValue>) -> Array;
type HeaderIterator = Map<Map<js_sys::IntoIter, F1>, fn(Array) -> (String, String)>;
impl IntoIterator for &Headers {
type Item = (String, String);
type IntoIter = HeaderIterator;
fn into_iter(self) -> Self::IntoIter {
self.entries()
}
}
impl<T: AsRef<str>> FromIterator<(T, T)> for Headers {
fn from_iter<U: IntoIterator<Item = (T, T)>>(iter: U) -> Self {
let mut headers = Headers::new();
iter.into_iter().for_each(|(name, value)| {
headers.append(name.as_ref(), value.as_ref()).ok();
});
headers
}
}
impl<'a, T: AsRef<str>> FromIterator<&'a (T, T)> for Headers {
fn from_iter<U: IntoIterator<Item = &'a (T, T)>>(iter: U) -> Self {
let mut headers = Headers::new();
iter.into_iter().for_each(|(name, value)| {
headers.append(name.as_ref(), value.as_ref()).ok();
});
headers
}
}
impl AsRef<JsValue> for Headers {
fn as_ref(&self) -> &JsValue {
&self.0
}
}
impl From<&HeaderMap> for Headers {
fn from(map: &HeaderMap) -> Self {
map.keys()
.flat_map(|name| {
map.get_all(name)
.into_iter()
.map(move |value| (name.to_string(), value.to_str().unwrap().to_owned()))
})
.collect()
}
}
impl From<HeaderMap> for Headers {
fn from(map: HeaderMap) -> Self {
(&map).into()
}
}
impl From<&Headers> for HeaderMap {
fn from(headers: &Headers) -> Self {
headers
.into_iter()
.map(|(name, value)| {
(
HeaderName::from_str(&name).unwrap(),
HeaderValue::from_str(&value).unwrap(),
)
})
.collect()
}
}
impl From<Headers> for HeaderMap {
fn from(headers: Headers) -> Self {
(&headers).into()
}
}
impl Clone for Headers {
fn clone(&self) -> Self {
Headers(EdgeHeaders::new_with_headers(&self.0).unwrap())
}
}