contacts_core/
property_find.rs1use bytes::Bytes;
2
3use crate::{
4 ns::*,
5 PropertyName,
6 PropertyResponse,
7 XmlError,
8 XmlReader,
9 XmlWriter,
10};
11
12#[derive(Debug)]
13pub enum PropertyFindRequest<Names> {
14 All,
15 AllInclude {
16 names: Names,
17 },
18 Names,
19 Values {
20 names: Names,
21 },
22}
23
24impl<'a, Names> PropertyFindRequest<Names>
25where
26 Names: IntoIterator<Item = &'a PropertyName>,
27{
28 pub fn to_xml(self) -> Result<Bytes, XmlError> {
29 let mut writer = XmlWriter::new();
30 writer.document()?;
31
32 writer.open_local_writer("propfind")
33 .default_ns(DAV)
34 .write()?;
35
36 match self {
37 Self::All => {
38 writer.empty_local("allprop")?;
39 }
40
41 Self::AllInclude { names } => {
42 writer.empty_local("allprop")?;
43
44 writer.open_local("include")?;
45 for name in names.into_iter() {
46 name.to_xml(&mut writer)?;
47 }
48 writer.close()?;
49 }
50
51 Self::Names => {
52 writer.empty_local("propname")?;
53 }
54
55 Self::Values { names } => {
56 writer.open_local("prop")?;
57 for name in names.into_iter() {
58 name.to_xml(&mut writer)?;
59 }
60 writer.close()?;
61 }
62 }
63
64 writer.close()?;
65
66 Ok(writer.freeze())
67 }
68}
69
70impl PropertyFindRequest<Vec<PropertyName>>
71{
72 pub fn from_xml(bytes: Bytes) -> Result<Self, XmlError> {
73 let value;
74 let mut reader = XmlReader::new(bytes)?;
75
76 reader.open(DAV, "propfind")?;
77 if reader.is_open(DAV, "allprop")? {
78 reader.close()?;
79
80 if reader.is_open(DAV, "include")? {
81 let mut names = Vec::new();
82
83 while reader.not_close() {
84 let name = PropertyResponse::from_xml(&mut reader)?
85 .to_name();
86 names.push(name);
87 }
88
89 value = PropertyFindRequest::AllInclude { names };
90 } else {
91 value = PropertyFindRequest::All;
92 }
93 } else if reader.is_open(DAV, "prop")? {
94 let mut names = Vec::new();
95
96 while reader.not_close() {
97 let name = PropertyResponse::from_xml(&mut reader)?
98 .to_name();
99 names.push(name);
100 }
101
102 value = PropertyFindRequest::Values { names };
103 } else if reader.is_open(DAV, "propname")? {
104 value = PropertyFindRequest::Names;
105 } else {
106 return reader.unexpected();
107 }
108 reader.close()?;
109
110 Ok(value)
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use std::assert_matches;
117
118 use super::{
119 PropertyName,
120 PropertyFindRequest,
121 };
122
123 #[test]
124 fn all_to_xml() {
125 let request: PropertyFindRequest<Option<&PropertyName>>
126 = PropertyFindRequest::All;
127 let bytes = request.to_xml().expect("to_xml");
128 let xml = std::str::from_utf8(&bytes).expect("utf8");
129 assert_eq!(xml, "\
130 <?xml version=\"1.0\" encoding=\"utf-8\"?>\
131 <propfind xmlns=\"DAV:\">\
132 <allprop/>\
133 </propfind>"
134 );
135 let request = PropertyFindRequest::from_xml(bytes).expect("from_xml");
136 assert_matches!(request, PropertyFindRequest::All);
137 }
138
139 #[test]
140 fn all_include_to_xml() {
141 let request = PropertyFindRequest::AllInclude {
142 names: Some(&PropertyName::CurrentUserPrincipal),
143 };
144 let bytes = request.to_xml().expect("to_xml");
145 let xml = std::str::from_utf8(&bytes).expect("utf8");
146 assert_eq!(xml, "\
147 <?xml version=\"1.0\" encoding=\"utf-8\"?>\
148 <propfind xmlns=\"DAV:\">\
149 <allprop/>\
150 <include>\
151 <current-user-principal/>\
152 </include>\
153 </propfind>"
154 );
155 let request = PropertyFindRequest::from_xml(bytes).expect("from_xml");
156 assert_matches!(request, PropertyFindRequest::AllInclude { .. });
157 if let PropertyFindRequest::AllInclude { names } = request {
158 assert_matches!(names.as_slice(), [
159 PropertyName::CurrentUserPrincipal,
160 ]);
161 }
162 }
163
164 #[test]
165 fn names_to_xml() {
166 let request: PropertyFindRequest<Option<&PropertyName>>
167 = PropertyFindRequest::Names;
168 let bytes = request.to_xml().expect("to_xml");
169 let xml = std::str::from_utf8(&bytes).expect("utf8");
170 assert_eq!(xml, "\
171 <?xml version=\"1.0\" encoding=\"utf-8\"?>\
172 <propfind xmlns=\"DAV:\">\
173 <propname/>\
174 </propfind>"
175 );
176 let request = PropertyFindRequest::from_xml(bytes).expect("from_xml");
177 assert_matches!(request, PropertyFindRequest::Names);
178 }
179
180 #[test]
181 fn values_to_xml() {
182 let request = PropertyFindRequest::Values {
183 names: &[
184 PropertyName::CurrentUserPrincipal,
185 PropertyName::ResourceType,
186 ],
187 };
188 let bytes = request.to_xml().expect("to_xml");
189 let xml = std::str::from_utf8(&bytes).expect("utf8");
190 assert_eq!(xml, "\
191 <?xml version=\"1.0\" encoding=\"utf-8\"?>\
192 <propfind xmlns=\"DAV:\">\
193 <prop>\
194 <current-user-principal/>\
195 <resourcetype/>\
196 </prop>\
197 </propfind>"
198 );
199 let request = PropertyFindRequest::from_xml(bytes).expect("from_xml");
200 assert_matches!(request, PropertyFindRequest::Values { .. });
201 if let PropertyFindRequest::Values { names } = request {
202 assert_matches!(names.as_slice(), [
203 PropertyName::CurrentUserPrincipal,
204 PropertyName::ResourceType,
205 ]);
206 }
207 }
208}
209