rustical_dav/xml/
propfind.rs

1use quick_xml::events::Event;
2use quick_xml::name::ResolveResult;
3use rustical_xml::NamespaceOwned;
4use rustical_xml::Unparsed;
5use rustical_xml::XmlDeserialize;
6use rustical_xml::XmlError;
7use rustical_xml::XmlRootTag;
8
9#[derive(Debug, Clone, XmlDeserialize, XmlRootTag, PartialEq)]
10#[xml(root = b"propfind", ns = "crate::namespace::NS_DAV")]
11pub struct PropfindElement<PN: XmlDeserialize> {
12    #[xml(ty = "untagged")]
13    pub prop: PropfindType<PN>,
14    #[xml(ns = "crate::namespace::NS_DAV")]
15    pub include: Option<PropElement<PN>>,
16}
17
18#[derive(Debug, Clone, PartialEq)]
19pub struct PropElement<PN: XmlDeserialize>(
20    // valid
21    pub Vec<PN>,
22    // invalid
23    pub Vec<(Option<NamespaceOwned>, String)>,
24);
25
26impl<PN: XmlDeserialize> XmlDeserialize for PropElement<PN> {
27    fn deserialize<R: std::io::BufRead>(
28        reader: &mut quick_xml::NsReader<R>,
29        start: &quick_xml::events::BytesStart,
30        empty: bool,
31    ) -> Result<Self, XmlError> {
32        if empty {
33            return Ok(Self(vec![], vec![]));
34        }
35        let mut buf = Vec::new();
36        let mut valid_props = vec![];
37        let mut invalid_props = vec![];
38        loop {
39            let event = reader.read_event_into(&mut buf)?;
40            match &event {
41                Event::End(e) if e.name() == start.name() => {
42                    break;
43                }
44                Event::Eof => return Err(XmlError::Eof),
45                // start of a child element
46                Event::Start(start) | Event::Empty(start) => {
47                    let empty = matches!(event, Event::Empty(_));
48                    let (ns, name) = reader.resolve_element(start.name());
49                    let ns = match ns {
50                        ResolveResult::Bound(ns) => Some(NamespaceOwned::from(ns)),
51                        ResolveResult::Unknown(_ns) => todo!("handle error"),
52                        ResolveResult::Unbound => None,
53                    };
54
55                    match PN::deserialize(reader, start, empty) {
56                        Ok(propname) => valid_props.push(propname),
57                        Err(XmlError::InvalidVariant(_)) => {
58                            invalid_props
59                                .push((ns, String::from_utf8_lossy(name.as_ref()).to_string()));
60                            // Consume content
61                            Unparsed::deserialize(reader, start, empty)?;
62                        }
63                        Err(err) => return Err(err),
64                    }
65                }
66                Event::Text(_) | Event::CData(_) => {
67                    return Err(XmlError::UnsupportedEvent("Not expecting text here"));
68                }
69                Event::Decl(_) | Event::Comment(_) | Event::DocType(_) | Event::PI(_) => { /* ignore */
70                }
71                Event::End(_end) => {
72                    unreachable!(
73                        "Unexpected closing tag for wrong element, should be handled by quick_xml"
74                    );
75                }
76            }
77        }
78        Ok(Self(valid_props, invalid_props))
79    }
80}
81
82#[derive(Debug, Clone, XmlDeserialize, PartialEq)]
83pub enum PropfindType<PN: XmlDeserialize> {
84    #[xml(ns = "crate::namespace::NS_DAV")]
85    Propname,
86    #[xml(ns = "crate::namespace::NS_DAV")]
87    Allprop,
88    #[xml(ns = "crate::namespace::NS_DAV")]
89    Prop(PropElement<PN>),
90}