use std::fmt::{Debug, Write};
use super::Cookie;
#[cfg(feature = "time")]
pub mod dep_time;
#[cfg(feature = "chrono")]
pub mod dep_chrono;
#[cfg(feature = "jiff")]
pub mod dep_jiff;
const REMOVE: &str = "Thu, 01 Jan 1970 00:00:00 GMT";
#[derive(Clone, Default)]
pub enum Expires {
Remove,
#[default]
Session,
Exp(ExpVal),
}
#[derive(Clone, Default)]
pub struct ExpVal {
#[cfg(feature = "time")]
time: Option<time::OffsetDateTime>,
#[cfg(feature = "chrono")]
chrono: Option<chrono::DateTime<chrono::Utc>>,
#[cfg(feature = "jiff")]
jiff: Option<jiff::Zoned>,
}
impl Expires {
pub fn remove() -> Self {
#![allow(unreachable_code)]
#[cfg(feature = "jiff")]
return Self::remove_jiff();
#[cfg(feature = "chrono")]
return Self::remove_chrono();
#[cfg(feature = "time")]
return Self::remove_time();
Self::Remove
}
}
impl Cookie {
pub fn expires_is_set(&self) -> bool {
!matches!(self.expires, Expires::Session)
}
pub(crate) fn serialize_expire(&self, buf: &mut String) -> crate::Result<()> {
match &self.expires {
#[cfg(feature = "time")]
Expires::Exp(ExpVal { time: Some(t), .. }) => dep_time::ser_expires(t, buf),
#[cfg(feature = "chrono")]
Expires::Exp(ExpVal {
chrono: Some(c), ..
}) => dep_chrono::ser_expires(c, buf),
#[cfg(feature = "jiff")]
Expires::Exp(ExpVal { jiff: Some(j), .. }) => dep_jiff::ser_expires(j, buf),
Expires::Remove => {
let _ = write!(buf, "; Expires={REMOVE}");
Ok(())
}
_ => Ok(()),
}
}
}
impl PartialEq for Expires {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Expires::Remove, Expires::Remove) => true,
(Expires::Session, Expires::Session) => true,
(Expires::Exp(_s), Expires::Exp(_o)) => {
#[cfg(feature = "time")]
if _s.time.is_some() || _o.time.is_some() {
return _s.time == _o.time;
}
#[cfg(feature = "chrono")]
if _s.chrono.is_some() || _o.chrono.is_some() {
return _s.chrono == _o.chrono;
}
#[cfg(feature = "jiff")]
if _s.jiff.is_some() || _o.jiff.is_some() {
return _s.jiff == _o.jiff;
}
true
}
_ => false,
}
}
}
#[cfg(all(test, feature = "time", feature = "jiff"))]
mod eq_tests {
use crate::Cookie;
use jiff::{civil::datetime, tz::TimeZone};
fn cookie_expiring(year: i16) -> Cookie {
Cookie::build("foo", "bar")
.expires(
datetime(year, 1, 1, 0, 0, 0, 0)
.to_zoned(TimeZone::UTC)
.unwrap(),
)
.build()
}
#[test]
fn different_expiry_is_not_equal() {
assert_ne!(cookie_expiring(2020), cookie_expiring(2099));
}
#[test]
fn same_expiry_is_equal() {
assert_eq!(cookie_expiring(2020), cookie_expiring(2020));
}
}
impl Debug for Expires {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Remove => write!(f, "{REMOVE}"),
Self::Session => write!(f, "Session"),
Self::Exp(_exp) => {
let mut debug = f.debug_struct("Exp");
#[cfg(feature = "time")]
let debug = debug.field("expires_time", &_exp.time);
#[cfg(feature = "chrono")]
let debug = debug.field("expires_chrono", &_exp.chrono);
#[cfg(feature = "jiff")]
let debug = debug.field("expires_jiff", &_exp.jiff);
debug.finish()
}
}
}
}