1use std::{fmt::Display, num::NonZeroU32, str::FromStr};
6
7use chrono::{DateTime, Local};
8use icalendar::Component;
9
10use crate::LooseDateTime;
11
12pub trait Event {
14 fn short_id(&self) -> Option<NonZeroU32> {
18 None
19 }
20
21 fn uid(&self) -> &str;
23
24 fn description(&self) -> Option<&str>;
26
27 fn start(&self) -> Option<LooseDateTime>;
29
30 fn end(&self) -> Option<LooseDateTime>;
32
33 fn status(&self) -> Option<EventStatus>;
35
36 fn summary(&self) -> &str;
38}
39
40impl Event for icalendar::Event {
41 fn uid(&self) -> &str {
42 self.get_uid().unwrap_or("")
43 }
44
45 fn description(&self) -> Option<&str> {
46 self.get_description()
47 }
48
49 fn start(&self) -> Option<LooseDateTime> {
50 self.get_start().map(Into::into)
51 }
52
53 fn end(&self) -> Option<LooseDateTime> {
54 self.get_end().map(Into::into)
55 }
56
57 fn status(&self) -> Option<EventStatus> {
58 self.get_status().map(EventStatus::from)
59 }
60
61 fn summary(&self) -> &str {
62 self.get_summary().unwrap_or("")
63 }
64}
65
66#[derive(Debug, Clone, Copy)]
68pub enum EventStatus {
69 Tentative,
71
72 Confirmed,
74
75 Cancelled,
77}
78
79const STATUS_TENTATIVE: &str = "TENTATIVE";
80const STATUS_CONFIRMED: &str = "CONFIRMED";
81const STATUS_CANCELLED: &str = "CANCELLED";
82
83impl AsRef<str> for EventStatus {
84 fn as_ref(&self) -> &str {
85 match self {
86 EventStatus::Tentative => STATUS_TENTATIVE,
87 EventStatus::Confirmed => STATUS_CONFIRMED,
88 EventStatus::Cancelled => STATUS_CANCELLED,
89 }
90 }
91}
92
93impl Display for EventStatus {
94 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95 write!(f, "{}", self.as_ref())
96 }
97}
98
99impl FromStr for EventStatus {
100 type Err = ();
101
102 fn from_str(value: &str) -> Result<Self, Self::Err> {
103 match value {
104 STATUS_TENTATIVE => Ok(EventStatus::Tentative),
105 STATUS_CONFIRMED => Ok(EventStatus::Confirmed),
106 STATUS_CANCELLED => Ok(EventStatus::Cancelled),
107 _ => Err(()),
108 }
109 }
110}
111
112impl From<EventStatus> for icalendar::EventStatus {
113 fn from(status: EventStatus) -> Self {
114 match status {
115 EventStatus::Tentative => icalendar::EventStatus::Tentative,
116 EventStatus::Confirmed => icalendar::EventStatus::Confirmed,
117 EventStatus::Cancelled => icalendar::EventStatus::Cancelled,
118 }
119 }
120}
121
122impl From<icalendar::EventStatus> for EventStatus {
123 fn from(status: icalendar::EventStatus) -> Self {
124 match status {
125 icalendar::EventStatus::Tentative => EventStatus::Tentative,
126 icalendar::EventStatus::Confirmed => EventStatus::Confirmed,
127 icalendar::EventStatus::Cancelled => EventStatus::Cancelled,
128 }
129 }
130}
131
132#[derive(Debug, Clone, Copy)]
134pub struct EventConditions {
135 pub startable: bool,
137}
138
139#[derive(Debug)]
140pub(crate) struct ParsedEventConditions {
141 pub end_after: Option<DateTime<Local>>,
143}
144
145impl ParsedEventConditions {
146 pub fn parse(now: &DateTime<Local>, conds: &EventConditions) -> Self {
147 Self {
148 end_after: conds.startable.then_some(*now),
149 }
150 }
151}