cookie_monster/cookie/expires/
mod.rs

1use std::fmt::{Debug, Write};
2
3use super::Cookie;
4
5#[cfg(feature = "time")]
6pub mod dep_time;
7
8#[cfg(feature = "chrono")]
9pub mod dep_chrono;
10
11#[cfg(feature = "jiff")]
12pub mod dep_jiff;
13
14const REMOVE: &str = "Thu, 01 Jan 1970 00:00:00 GMT";
15
16#[derive(Clone, Default)]
17pub enum Expires {
18    // So a user can still remove a cookie without needing any of the datetime features.
19    Remove,
20    // No expiry time.
21    #[default]
22    Session,
23    Exp(ExpVal),
24}
25
26#[derive(Clone, Default)]
27pub struct ExpVal {
28    #[cfg(feature = "time")]
29    time: Option<time::OffsetDateTime>,
30    #[cfg(feature = "chrono")]
31    chrono: Option<chrono::DateTime<chrono::Utc>>,
32    #[cfg(feature = "jiff")]
33    jiff: Option<jiff::Zoned>,
34}
35
36impl Expires {
37    pub fn remove() -> Self {
38        #![allow(unreachable_code)]
39
40        #[cfg(feature = "jiff")]
41        return Self::remove_jiff();
42
43        #[cfg(feature = "chrono")]
44        return Self::remove_chrono();
45
46        #[cfg(feature = "time")]
47        return Self::remove_time();
48
49        Self::Remove
50    }
51}
52
53impl Cookie {
54    pub fn serialize_expire(&self, buf: &mut String) -> crate::Result<()> {
55        // Only one can be set at all times, except while parsing but then the first match is used.
56        match &self.expires {
57            #[cfg(feature = "time")]
58            Expires::Exp(ExpVal { time: Some(t), .. }) => dep_time::ser_expires(t, buf),
59            #[cfg(feature = "chrono")]
60            Expires::Exp(ExpVal {
61                chrono: Some(c), ..
62            }) => dep_chrono::ser_expires(c, buf),
63            #[cfg(feature = "jiff")]
64            Expires::Exp(ExpVal { jiff: Some(j), .. }) => dep_jiff::ser_expires(j, buf),
65            Expires::Remove => {
66                let _ = write!(buf, "; Expires={REMOVE}");
67                Ok(())
68            }
69
70            _ => Ok(()),
71        }
72    }
73}
74
75impl PartialEq for Expires {
76    fn eq(&self, other: &Self) -> bool {
77        match (self, other) {
78            (Expires::Remove, Expires::Remove) => true,
79            (Expires::Session, Expires::Session) => true,
80            (Expires::Exp(_s), Expires::Exp(_o)) => {
81                // TODO: double check this.
82                #[cfg(feature = "time")]
83                if _s.time == _o.time {
84                    return true;
85                }
86
87                #[cfg(feature = "chrono")]
88                if _s.chrono == _o.chrono {
89                    return true;
90                }
91                #[cfg(feature = "jiff")]
92                if _s.jiff == _o.jiff {
93                    return true;
94                }
95
96                false
97            }
98            _ => false,
99        }
100    }
101}
102
103impl Debug for Expires {
104    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105        match self {
106            Self::Remove => write!(f, "{REMOVE}"),
107            Self::Session => write!(f, "Session"),
108            Self::Exp(_exp) => {
109                let mut debug = f.debug_struct("Exp");
110
111                #[cfg(feature = "time")]
112                let debug = debug.field("expires_time", &_exp.time);
113
114                #[cfg(feature = "chrono")]
115                let debug = debug.field("expires_chrono", &_exp.chrono);
116
117                #[cfg(feature = "jiff")]
118                let debug = debug.field("expires_jiff", &_exp.jiff);
119
120                debug.finish()
121            }
122        }
123    }
124}