rustical_dav/xml/
propfind.rs1use 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, Eq)]
10#[xml(root = "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, Eq)]
19pub struct PropElement<PN: XmlDeserialize>(
20 pub Vec<PN>,
22 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 Event::Start(start) | Event::Empty(start) => {
47 let empty = matches!(event, Event::Empty(_));
48 let (ns, name) = reader.resolver().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 Unparsed::deserialize(reader, start, empty)?;
62 }
63 Err(err) => return Err(err),
64 }
65 }
66 Event::Text(text) => {
67 if text.xml_content()?.chars().any(|chr| !chr.is_whitespace()) {
68 return Err(::rustical_xml::XmlError::UnsupportedEvent(
69 "unexpected text",
70 ));
71 }
72 }
73 Event::CData(_) => {
74 return Err(XmlError::UnsupportedEvent("Not expecting text here"));
75 }
76 Event::GeneralRef(_) => {
77 return Err(::rustical_xml::XmlError::UnsupportedEvent("GeneralRef"));
78 }
79 Event::Decl(_) | Event::Comment(_) | Event::DocType(_) | Event::PI(_) => { }
81 Event::End(_end) => {
82 unreachable!(
83 "Unexpected closing tag for wrong element, should be handled by quick_xml"
84 );
85 }
86 }
87 }
88 Ok(Self(valid_props, invalid_props))
89 }
90}
91
92#[derive(Debug, Clone, XmlDeserialize, PartialEq, Eq)]
93pub enum PropfindType<PN: XmlDeserialize> {
94 #[xml(ns = "crate::namespace::NS_DAV")]
95 Propname,
96 #[xml(ns = "crate::namespace::NS_DAV")]
97 Allprop,
98 #[xml(ns = "crate::namespace::NS_DAV")]
99 Prop(PropElement<PN>),
100}