fix parsing

This commit is contained in:
Quentin 2024-03-12 10:18:13 +01:00
parent 6d1f538091
commit 442433d70b
Signed by: quentin
GPG key ID: E9602264D639FF68
4 changed files with 185 additions and 72 deletions

View file

@ -356,26 +356,42 @@ impl QRead<CalendarDataEmpty> for CalendarDataEmpty {
}
impl QRead<Comp> for Comp {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
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<CompInner> for CompInner {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
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<PropKind>, Option<CompKind>) = (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<CompInner> 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<CompSupport> for CompSupport {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
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<CompKind> 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<PropKind> 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<TimeZone> for TimeZone {
impl QRead<Filter> for Filter {
async fn qread(xml: &mut Reader<impl IRead>) -> Result<Self, ParsingError> {
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<CalProp> 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]]></C:calendar-timezone>
let got = deserialize::<MkCalendar<Calendar>>(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#"
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:D="DAV:"
xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<D:getetag/>
<C:calendar-data>
<C:comp name="VCALENDAR">
<C:prop name="VERSION"/>
<C:comp name="VEVENT">
<C:prop name="SUMMARY"/>
<C:prop name="UID"/>
<C:prop name="DTSTART"/>
<C:prop name="DTEND"/>
<C:prop name="DURATION"/>
<C:prop name="RRULE"/>
<C:prop name="RDATE"/>
<C:prop name="EXRULE"/>
<C:prop name="EXDATE"/>
<C:prop name="RECURRENCE-ID"/>
</C:comp>
<C:comp name="VTIMEZONE"/>
</C:comp>
</C:calendar-data>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:time-range start="20060104T000000Z"
end="20060105T000000Z"/>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
"#;
let got = deserialize::<CalendarQuery<Calendar>>(src).await;
assert_eq!(got, expected)
}
}

View file

@ -353,23 +353,21 @@ impl QWrite for CalendarDataEmpty {
}
}
impl QWrite for CompInner {
async fn qwrite(&self, _xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
unreachable!();
}
}
impl QWrite for Comp {
async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> 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,
})),

View file

@ -855,13 +855,8 @@ pub struct CalendarDataSupport {
#[derive(Debug, PartialEq)]
pub struct Comp {
pub name: Component,
pub additional_rules: Option<CompInner>,
}
#[derive(Debug, PartialEq)]
pub struct CompInner {
pub prop_kind: PropKind,
pub comp_kind: CompKind,
pub prop_kind: Option<PropKind>,
pub comp_kind: Option<CompKind>,
}
/// For SupportedCalendarComponentSet

View file

@ -128,6 +128,10 @@ impl<T: IRead> Reader<T> {
&self.cur
}
pub fn previous(&self) -> &Event<'static> {
&self.prev
}
// NEW API
pub async fn tag_string(&mut self) -> Result<String, ParsingError> {
self.ensure_parent_has_child()?;