From 5e5017a1858498043147ae9297a917ccfb91fb5d Mon Sep 17 00:00:00 2001 From: Lennart K <18233294+lennart-k@users.noreply.github.com> Date: Wed, 7 Jan 2026 11:46:28 +0100 Subject: [PATCH] Decrease folder nesting --- crates/ical/src/calendar_object.rs | 136 ++++++++++++++++++ .../src/{icalendar/object.rs => icalendar.rs} | 0 crates/ical/src/icalendar/mod.rs | 3 - crates/ical/src/lib.rs | 4 +- 4 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 crates/ical/src/calendar_object.rs rename crates/ical/src/{icalendar/object.rs => icalendar.rs} (100%) delete mode 100644 crates/ical/src/icalendar/mod.rs diff --git a/crates/ical/src/calendar_object.rs b/crates/ical/src/calendar_object.rs new file mode 100644 index 0000000..7035e49 --- /dev/null +++ b/crates/ical/src/calendar_object.rs @@ -0,0 +1,136 @@ +use crate::Error; +use chrono::DateTime; +use chrono::Utc; +use derive_more::Display; +use ical::component::CalendarInnerData; +use ical::component::IcalCalendarObject; +use ical::parser::ComponentParser; +use serde::Deserialize; +use serde::Serialize; +use sha2::{Digest, Sha256}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Display)] +// specified in https://datatracker.ietf.org/doc/html/rfc5545#section-3.6 +pub enum CalendarObjectType { + #[serde(rename = "VEVENT")] + Event = 0, + #[serde(rename = "VTODO")] + Todo = 1, + #[serde(rename = "VJOURNAL")] + Journal = 2, +} + +impl From<&IcalCalendarObject> for CalendarObjectType { + fn from(value: &IcalCalendarObject) -> Self { + match value.get_inner() { + CalendarInnerData::Event(_, _) => Self::Event, + CalendarInnerData::Todo(_, _) => Self::Todo, + CalendarInnerData::Journal(_, _) => Self::Journal, + } + } +} + +impl CalendarObjectType { + #[must_use] + pub const fn as_str(&self) -> &'static str { + match self { + Self::Event => "VEVENT", + Self::Todo => "VTODO", + Self::Journal => "VJOURNAL", + } + } +} + +impl rustical_xml::ValueSerialize for CalendarObjectType { + fn serialize(&self) -> String { + self.as_str().to_owned() + } +} + +impl rustical_xml::ValueDeserialize for CalendarObjectType { + fn deserialize(val: &str) -> std::result::Result { + match ::deserialize(val)?.as_str() { + "VEVENT" => Ok(Self::Event), + "VTODO" => Ok(Self::Todo), + "VJOURNAL" => Ok(Self::Journal), + _ => Err(rustical_xml::XmlError::InvalidValue( + rustical_xml::ParseValueError::Other(format!( + "Invalid value '{val}', must be VEVENT, VTODO, or VJOURNAL" + )), + )), + } + } +} + +#[derive(Debug, Clone)] +pub struct CalendarObject { + id: String, + inner: IcalCalendarObject, + ics: String, +} + +impl CalendarObject { + pub fn from_ics(ics: String, id: Option) -> Result { + let mut parser: ComponentParser<_, IcalCalendarObject> = + ComponentParser::new(ics.as_bytes()); + let inner = parser.next().ok_or(Error::MissingCalendar)??; + if parser.next().is_some() { + return Err(Error::InvalidData( + "multiple calendars, only one allowed".to_owned(), + )); + } + + Ok(Self { + id: id.unwrap_or_else(|| inner.get_uid().to_owned()), + inner, + ics, + }) + } + + #[must_use] + pub const fn get_inner(&self) -> &IcalCalendarObject { + &self.inner + } + + #[must_use] + pub fn get_uid(&self) -> &str { + self.inner.get_uid() + } + + #[must_use] + pub fn get_id(&self) -> &str { + &self.id + } + + #[must_use] + pub fn get_etag(&self) -> String { + let mut hasher = Sha256::new(); + hasher.update(self.get_uid()); + hasher.update(self.get_ics()); + format!("\"{:x}\"", hasher.finalize()) + } + + #[must_use] + pub fn get_ics(&self) -> &str { + &self.ics + } + + #[must_use] + pub fn get_component_name(&self) -> &str { + self.get_object_type().as_str() + } + + #[must_use] + pub fn get_object_type(&self) -> CalendarObjectType { + (&self.inner).into() + } + + pub fn expand_recurrence( + &self, + start: Option>, + end: Option>, + ) -> Result { + // Ok(self.inner.expand_recurrence(start, end)?) + todo!() + } +} diff --git a/crates/ical/src/icalendar/object.rs b/crates/ical/src/icalendar.rs similarity index 100% rename from crates/ical/src/icalendar/object.rs rename to crates/ical/src/icalendar.rs diff --git a/crates/ical/src/icalendar/mod.rs b/crates/ical/src/icalendar/mod.rs deleted file mode 100644 index 75ce6bc..0000000 --- a/crates/ical/src/icalendar/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod object; - -pub use object::*; diff --git a/crates/ical/src/lib.rs b/crates/ical/src/lib.rs index 42f646f..7e1aa43 100644 --- a/crates/ical/src/lib.rs +++ b/crates/ical/src/lib.rs @@ -3,8 +3,8 @@ mod timestamp; pub use timestamp::*; -mod icalendar; -pub use icalendar::*; +mod calendar_object; +pub use calendar_object::*; mod error; pub use error::Error;