Skip to main content

contacts_core/
property_find.rs

1use 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