From 442433d70bf13b1641ec76077d9955f5d63ee965 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Tue, 12 Mar 2024 10:18:13 +0100 Subject: [PATCH] fix parsing --- aero-dav/src/caldecoder.rs | 183 ++++++++++++++++++++++++++++++------- aero-dav/src/calencoder.rs | 61 ++++++------- aero-dav/src/caltypes.rs | 9 +- aero-dav/src/xml.rs | 4 + 4 files changed, 185 insertions(+), 72 deletions(-) diff --git a/aero-dav/src/caldecoder.rs b/aero-dav/src/caldecoder.rs index 239b005..2e833a1 100644 --- a/aero-dav/src/caldecoder.rs +++ b/aero-dav/src/caldecoder.rs @@ -356,26 +356,42 @@ impl QRead for CalendarDataEmpty { } impl QRead for Comp { - async fn qread(xml: &mut Reader) -> Result { - xml.open(CAL_URN, "comp").await?; - let name = Component::new(xml.prev_attr("name").ok_or(ParsingError::MissingAttribute)?); - let additional_rules = Box::pin(xml.maybe_find()).await?; - xml.close().await?; - Ok(Self { name, additional_rules }) - } -} - -impl QRead for CompInner { async fn qread(xml: &mut Reader) -> Result { let (mut prop_kind, mut comp_kind) = (None, None); + let bs = xml.open(CAL_URN, "comp").await?; + let name = Component::new(xml.prev_attr("name").ok_or(ParsingError::MissingAttribute)?); + + // Return early if it's an empty tag + if matches!(bs, Event::Empty(_)) { + xml.close().await?; + return Ok(Self { name, prop_kind, comp_kind }) + } + loop { let mut dirty = false; - - xml.maybe_read(&mut prop_kind, &mut dirty).await?; - xml.maybe_read(&mut comp_kind, &mut dirty).await?; + let (mut tmp_prop_kind, mut tmp_comp_kind): (Option, Option) = (None, None); - if !dirty { + xml.maybe_read(&mut tmp_prop_kind, &mut dirty).await?; + Box::pin(xml.maybe_read(&mut tmp_comp_kind, &mut dirty)).await?; + + //@FIXME hack + // Merge + match (tmp_prop_kind, &mut prop_kind) { + (Some(PropKind::Prop(mut a)), Some(PropKind::Prop(ref mut b))) => b.append(&mut a), + (Some(PropKind::AllProp), v) => *v = Some(PropKind::AllProp), + (Some(x), b) => *b = Some(x), + (None, _) => (), + }; + match (tmp_comp_kind, &mut comp_kind) { + (Some(CompKind::Comp(mut a)), Some(CompKind::Comp(ref mut b))) => b.append(&mut a), + (Some(CompKind::AllComp), v) => *v = Some(CompKind::AllComp), + (Some(a), b) => *b = Some(a), + (None, _) => (), + }; + + + if !dirty { match xml.peek() { Event::End(_) => break, _ => xml.skip().await?, @@ -383,19 +399,15 @@ impl QRead for CompInner { } }; - match (prop_kind, comp_kind) { - (Some(prop_kind), Some(comp_kind)) => Ok(Self { prop_kind, comp_kind }), - _ => Err(ParsingError::MissingChild), - } + xml.close().await?; + Ok(Self { name, prop_kind, comp_kind }) } } impl QRead for CompSupport { async fn qread(xml: &mut Reader) -> Result { xml.open(CAL_URN, "comp").await?; - println!("before"); let inner = Component::new(xml.prev_attr("name").ok_or(ParsingError::MissingAttribute)?); - println!("after"); xml.close().await?; Ok(Self(inner)) } @@ -415,13 +427,13 @@ impl QRead for CompKind { xml.maybe_push(&mut comp, &mut dirty).await?; if !dirty { - match xml.peek() { - Event::End(_) => break, - _ => xml.skip().await?, - }; + break } } - Ok(CompKind::Comp(comp)) + match &comp[..] { + [] => Err(ParsingError::Recoverable), + _ => Ok(CompKind::Comp(comp)), + } } } @@ -439,13 +451,14 @@ impl QRead for PropKind { xml.maybe_push(&mut prop, &mut dirty).await?; if !dirty { - match xml.peek() { - Event::End(_) => break, - _ => xml.skip().await?, - }; + break } } - Ok(PropKind::Prop(prop)) + + match &prop[..] { + [] => Err(ParsingError::Recoverable), + _ => Ok(PropKind::Prop(prop)), + } } } @@ -687,7 +700,7 @@ impl QRead for TimeZone { impl QRead for Filter { async fn qread(xml: &mut Reader) -> Result { - xml.open(CAL_URN, "timezone").await?; + xml.open(CAL_URN, "filter").await?; let comp_filter = xml.find().await?; xml.close().await?; Ok(Self(comp_filter)) @@ -736,7 +749,7 @@ impl QRead for CalProp { #[cfg(test)] mod tests { use super::*; - //use chrono::{FixedOffset, TimeZone}; + use chrono::{Utc, TimeZone}; use crate::realization::Calendar; //use quick_reader::NsReader; @@ -803,4 +816,110 @@ END:VCALENDAR]]> let got = deserialize::>(src).await; assert_eq!(got, expected) } + + #[tokio::test] + async fn rfc_calendar_query() { + let expected = CalendarQuery { + selector: Some(CalendarSelector::Prop(dav::PropName(vec![ + dav::PropertyRequest::GetEtag, + dav::PropertyRequest::Extension(PropertyRequest::CalendarData(CalendarDataRequest { + mime: None, + comp: Some(Comp { + name: Component::VCalendar, + prop_kind: Some(PropKind::Prop(vec![ + CalProp { + name: ComponentProperty("VERSION".into()), + novalue: None, + } + ])), + comp_kind: Some(CompKind::Comp(vec![ + Comp { + name: Component::VEvent, + prop_kind: Some(PropKind::Prop(vec![ + CalProp { name: ComponentProperty("SUMMARY".into()), novalue: None }, + CalProp { name: ComponentProperty("UID".into()), novalue: None }, + CalProp { name: ComponentProperty("DTSTART".into()), novalue: None }, + CalProp { name: ComponentProperty("DTEND".into()), novalue: None }, + CalProp { name: ComponentProperty("DURATION".into()), novalue: None }, + CalProp { name: ComponentProperty("RRULE".into()), novalue: None }, + CalProp { name: ComponentProperty("RDATE".into()), novalue: None }, + CalProp { name: ComponentProperty("EXRULE".into()), novalue: None }, + CalProp { name: ComponentProperty("EXDATE".into()), novalue: None }, + CalProp { name: ComponentProperty("RECURRENCE-ID".into()), novalue: None }, + ])), + comp_kind: None, + }, + Comp { + name: Component::VTimeZone, + prop_kind: None, + comp_kind: None, + } + ])), + }), + recurrence: None, + limit_freebusy_set: None, + })), + ]))), + filter: Filter(CompFilter { + name: Component::VCalendar, + additional_rules: Some(CompFilterRules::Matches(CompFilterMatch { + prop_filter: vec![], + comp_filter: vec![ + CompFilter { + name: Component::VEvent, + additional_rules: Some(CompFilterRules::Matches(CompFilterMatch { + prop_filter: vec![], + comp_filter: vec![], + time_range: Some(TimeRange::FullRange( + Utc.with_ymd_and_hms(2006, 1, 4, 0, 0, 0).unwrap(), + Utc.with_ymd_and_hms(2006, 1, 5, 0, 0, 0).unwrap(), + )), + })), + }, + ], + time_range: None, + })), + }), + timezone: None, + }; + + let src = r#" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"#; + + let got = deserialize::>(src).await; + assert_eq!(got, expected) + } } diff --git a/aero-dav/src/calencoder.rs b/aero-dav/src/calencoder.rs index 6ad9f41..fff4d47 100644 --- a/aero-dav/src/calencoder.rs +++ b/aero-dav/src/calencoder.rs @@ -353,23 +353,21 @@ impl QWrite for CalendarDataEmpty { } } -impl QWrite for CompInner { - async fn qwrite(&self, _xml: &mut Writer) -> Result<(), QError> { - unreachable!(); - } -} - impl QWrite for Comp { async fn qwrite(&self, xml: &mut Writer) -> Result<(), QError> { let mut start = xml.create_cal_element("comp"); start.push_attribute(("name", self.name.as_str())); - match &self.additional_rules { - None => xml.q.write_event_async(Event::Empty(start)).await, - Some(rules) => { + match (&self.prop_kind, &self.comp_kind) { + (None, None) => xml.q.write_event_async(Event::Empty(start)).await, + _ => { let end = start.to_end(); xml.q.write_event_async(Event::Start(start.clone())).await?; - rules.prop_kind.qwrite(xml).await?; - rules.comp_kind.qwrite(xml).await?; + if let Some(prop_kind) = &self.prop_kind { + prop_kind.qwrite(xml).await?; + } + if let Some(comp_kind) = &self.comp_kind { + comp_kind.qwrite(xml).await?; + } xml.q.write_event_async(Event::End(end)).await }, } @@ -721,39 +719,36 @@ mod tests { mime: None, comp: Some(Comp { name: Component::VCalendar, - additional_rules: Some(CompInner { - prop_kind: PropKind::Prop(vec![ + prop_kind: Some(PropKind::Prop(vec![ CalProp { name: ComponentProperty("VERSION".into()), novalue: None, } - ]), - comp_kind: CompKind::Comp(vec![ + ])), + comp_kind: Some(CompKind::Comp(vec![ Comp { name: Component::VEvent, - additional_rules: Some(CompInner { - prop_kind: PropKind::Prop(vec![ - CalProp { name: ComponentProperty("SUMMARY".into()), novalue: None }, - CalProp { name: ComponentProperty("UID".into()), novalue: None }, - CalProp { name: ComponentProperty("DTSTART".into()), novalue: None }, - CalProp { name: ComponentProperty("DTEND".into()), novalue: None }, - CalProp { name: ComponentProperty("DURATION".into()), novalue: None }, - CalProp { name: ComponentProperty("RRULE".into()), novalue: None }, - CalProp { name: ComponentProperty("RDATE".into()), novalue: None }, - CalProp { name: ComponentProperty("EXRULE".into()), novalue: None }, - CalProp { name: ComponentProperty("EXDATE".into()), novalue: None }, - CalProp { name: ComponentProperty("RECURRENCE-ID".into()), novalue: None }, - ]), - comp_kind: CompKind::Comp(vec![]), - }), + prop_kind: Some(PropKind::Prop(vec![ + CalProp { name: ComponentProperty("SUMMARY".into()), novalue: None }, + CalProp { name: ComponentProperty("UID".into()), novalue: None }, + CalProp { name: ComponentProperty("DTSTART".into()), novalue: None }, + CalProp { name: ComponentProperty("DTEND".into()), novalue: None }, + CalProp { name: ComponentProperty("DURATION".into()), novalue: None }, + CalProp { name: ComponentProperty("RRULE".into()), novalue: None }, + CalProp { name: ComponentProperty("RDATE".into()), novalue: None }, + CalProp { name: ComponentProperty("EXRULE".into()), novalue: None }, + CalProp { name: ComponentProperty("EXDATE".into()), novalue: None }, + CalProp { name: ComponentProperty("RECURRENCE-ID".into()), novalue: None }, + ])), + comp_kind: None, }, Comp { name: Component::VTimeZone, - additional_rules: None, + prop_kind: None, + comp_kind: None, } - ]), + ])), }), - }), recurrence: None, limit_freebusy_set: None, })), diff --git a/aero-dav/src/caltypes.rs b/aero-dav/src/caltypes.rs index a6ea7ce..628ec4b 100644 --- a/aero-dav/src/caltypes.rs +++ b/aero-dav/src/caltypes.rs @@ -855,13 +855,8 @@ pub struct CalendarDataSupport { #[derive(Debug, PartialEq)] pub struct Comp { pub name: Component, - pub additional_rules: Option, -} - -#[derive(Debug, PartialEq)] -pub struct CompInner { - pub prop_kind: PropKind, - pub comp_kind: CompKind, + pub prop_kind: Option, + pub comp_kind: Option, } /// For SupportedCalendarComponentSet diff --git a/aero-dav/src/xml.rs b/aero-dav/src/xml.rs index 347a123..2f3b7a6 100644 --- a/aero-dav/src/xml.rs +++ b/aero-dav/src/xml.rs @@ -128,6 +128,10 @@ impl Reader { &self.cur } + pub fn previous(&self) -> &Event<'static> { + &self.prev + } + // NEW API pub async fn tag_string(&mut self) -> Result { self.ensure_parent_has_child()?;