use std::{borrow::Borrow, collections::HashSet, fmt::Debug, hash::Hash};
use crate::Cookie;
#[derive(Default, Debug)]
pub struct CookieJar {
cookies: HashSet<HashCookie>,
}
pub(crate) enum HashCookie {
Original(Cookie),
New(Cookie),
Removal(Cookie),
}
impl HashCookie {
fn name(&self) -> &str {
match self {
HashCookie::Original(c) => c.name(),
HashCookie::New(c) => c.name(),
HashCookie::Removal(c) => c.name(),
}
}
}
impl Hash for HashCookie {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.name().hash(state);
}
}
impl PartialEq for HashCookie {
fn eq(&self, other: &Self) -> bool {
self.name() == other.name()
}
}
impl Borrow<str> for HashCookie {
fn borrow(&self) -> &str {
self.name()
}
}
impl Eq for HashCookie {}
impl Debug for HashCookie {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
HashCookie::Original(cookie) => cookie.fmt(f),
HashCookie::New(cookie) => cookie.fmt(f),
HashCookie::Removal(cookie) => cookie.fmt(f),
}
}
}
impl CookieJar {
pub fn new() -> Self {
Self::default()
}
pub fn from_cookie(header: &str) -> Self {
Self::from_original(header.split(';').flat_map(Cookie::parse_cookie))
}
#[cfg(feature = "percent-encode")]
pub fn from_encoded_cookie(header: &str) -> Self {
Self::from_original(header.split(';').flat_map(Cookie::parse_cookie_encoded))
}
pub fn add_original(&mut self, cookie: Cookie) {
self.cookies.replace(HashCookie::Original(cookie));
}
pub fn from_original<T: IntoIterator<Item = Cookie>>(cookies: T) -> Self {
let mut jar = Self::new();
for cookie in cookies {
jar.add_original(cookie);
}
jar
}
pub fn get(&self, name: &str) -> Option<&Cookie> {
self.cookies.get(name).and_then(|c| match c {
HashCookie::New(c) | HashCookie::Original(c) => Some(c),
HashCookie::Removal(_) => None,
})
}
pub fn set_cookie_headers(&self) -> impl Iterator<Item = crate::Result<String>> {
self.cookies
.iter()
.filter_map(|c| match c {
HashCookie::Original(_) => None,
HashCookie::New(c) | HashCookie::Removal(c) => Some(c),
})
.map(Cookie::serialize)
}
pub fn remove(&mut self, cookie: impl Into<Cookie>) -> Option<Cookie> {
let cookie = HashCookie::Removal(cookie.into().into_remove());
self.cookies.replace(cookie).and_then(|c| match c {
HashCookie::Original(cookie) => Some(cookie),
HashCookie::New(cookie) => Some(cookie),
HashCookie::Removal(_) => None,
})
}
pub fn add(&mut self, cookie: impl Into<Cookie>) {
self.cookies.replace(HashCookie::New(cookie.into()));
}
#[allow(unused)]
pub(crate) fn iter_non_original(&self) -> impl Iterator<Item = &Cookie> {
self.cookies.iter().flat_map(|cookie| match cookie {
HashCookie::Original(_) => None,
HashCookie::New(cookie) | HashCookie::Removal(cookie) => Some(cookie),
})
}
}