use std::{ops::Deref, str::FromStr};
use headers::{HeaderValue, Host};
use http::uri::Authority;
use once_cell::sync::Lazy;
use crate::field::rules::{
flat_csv::{split_field_params, SemiColon},
parameter_name::FieldParameterName,
parameter_value::FieldParameterValue,
parameters::{FieldParameters, InvalidEncodedFieldParameters},
};
#[derive(Debug, Clone)]
pub struct ForwardedElement {
pub params: FieldParameters,
}
impl FromStr for ForwardedElement {
type Err = InvalidEncodedFieldParameters;
fn from_str(value: &str) -> Result<Self, Self::Err> {
let forwarded_pairs = split_field_params::<SemiColon>(value);
let params = FieldParameters::decode(forwarded_pairs, false)?;
Ok(Self { params })
}
}
impl From<&ForwardedElement> for HeaderValue {
#[inline]
fn from(element: &ForwardedElement) -> Self {
HeaderValue::from_str(element.str_encode().as_str()).expect("Must be valid header value")
}
}
impl ForwardedElement {
#[inline]
pub fn push_encoded_str(&self, buffer: &mut String) {
self.params.push_encoded_str(buffer);
}
pub fn str_encode(&self) -> String {
let mut encoded = String::new();
self.push_encoded_str(&mut encoded);
encoded
}
#[inline]
pub fn host(&self) -> Option<&FieldParameterValue> {
self.params.get_value(FWD_PARAM_HOST.deref())
}
pub fn host_decoded(&self) -> Option<Host> {
self.host()
.and_then(|host_val| Authority::from_str(host_val).ok())
.map(|authority| authority.into())
}
#[inline]
pub fn proto(&self) -> Option<&FieldParameterValue> {
self.params.get_value(FWD_PARAM_PROTO.deref())
}
}
pub static FWD_PARAM_BY: Lazy<FieldParameterName> =
Lazy::new(|| "by".parse().expect("Must be valid param key."));
pub static FWD_PARAM_FOR: Lazy<FieldParameterName> =
Lazy::new(|| "for".parse().expect("Must be valid param key."));
pub static FWD_PARAM_HOST: Lazy<FieldParameterName> =
Lazy::new(|| "host".parse().expect("Must be valid param key."));
pub static FWD_PARAM_PROTO: Lazy<FieldParameterName> =
Lazy::new(|| "proto".parse().expect("Must be valid param key."));