use std::marker::PhantomData;
use std::borrow::{Borrow, BorrowMut, Cow};
use crate::{CookieJar, Cookie};
pub struct PrefixedJar<P: Prefix, J> {
parent: J,
_prefix: PhantomData<fn() -> P>,
}
pub struct Host;
pub struct Secure;
pub trait Prefix: private::Sealed {
const PREFIX: &'static str;
#[allow(non_upper_case_globals)]
const Host: Host = Host;
#[allow(non_upper_case_globals)]
const Secure: Secure = Secure;
fn conform(cookie: Cookie<'_>) -> Cookie<'_>;
#[doc(hidden)]
#[inline(always)]
fn prefixed_name(name: &str) -> String {
format!("{}{}", Self::PREFIX, name)
}
#[doc(hidden)]
fn prefix(mut cookie: Cookie<'_>) -> Cookie<'_> {
use crate::CookieStr;
cookie.name = CookieStr::Concrete(match cookie.name {
CookieStr::Concrete(Cow::Owned(mut string)) => {
string.insert_str(0, Self::PREFIX);
string.into()
}
_ => Self::prefixed_name(cookie.name()).into(),
});
cookie
}
#[doc(hidden)]
fn clip(mut cookie: Cookie<'_>) -> Cookie<'_> {
use std::borrow::Cow::*;
use crate::CookieStr::*;
if !cookie.name().starts_with(Self::PREFIX) {
return cookie;
}
let len = Self::PREFIX.len();
cookie.name = match cookie.name {
Indexed(i, j) => Indexed(i + len, j),
Concrete(Borrowed(v)) => Concrete(Borrowed(&v[len..])),
Concrete(Owned(v)) => Concrete(Owned(v[len..].to_string())),
};
cookie
}
#[inline]
#[doc(hidden)]
fn apply(cookie: Cookie<'_>) -> Cookie<'_> {
Self::conform(Self::prefix(cookie))
}
}
impl<P: Prefix, J> PrefixedJar<P, J> {
#[inline(always)]
pub(crate) fn new(parent: J) -> Self {
Self { parent, _prefix: PhantomData }
}
}
impl<P: Prefix, J: Borrow<CookieJar>> PrefixedJar<P, J> {
pub fn get(&self, name: &str) -> Option<Cookie<'static>> {
self.parent.borrow()
.get(&P::prefixed_name(name))
.map(|c| P::clip(c.clone()))
}
}
impl<P: Prefix, J: BorrowMut<CookieJar>> PrefixedJar<P, J> {
pub fn add<C: Into<Cookie<'static>>>(&mut self, cookie: C) {
self.parent.borrow_mut().add(P::apply(cookie.into()));
}
pub fn add_original<C: Into<Cookie<'static>>>(&mut self, cookie: C) {
self.parent.borrow_mut().add_original(P::apply(cookie.into()));
}
pub fn remove<C: Into<Cookie<'static>>>(&mut self, cookie: C) {
self.parent.borrow_mut().remove(P::apply(cookie.into()));
}
}
impl Prefix for Host {
const PREFIX: &'static str = "__Host-";
fn conform(mut cookie: Cookie<'_>) -> Cookie<'_> {
cookie.set_secure(true);
cookie.set_path("/");
cookie.unset_domain();
cookie
}
}
impl Prefix for Secure {
const PREFIX: &'static str = "__Secure-";
fn conform(mut cookie: Cookie<'_>) -> Cookie<'_> {
cookie.set_secure(true);
cookie
}
}
mod private {
pub trait Sealed {}
impl Sealed for super::Host {}
impl Sealed for super::Secure {}
}