rustical_dav/xml/
sync_collection.rs

1use rustical_xml::{ValueDeserialize, ValueSerialize, XmlDeserialize, XmlRootTag};
2
3use super::PropfindType;
4
5#[derive(Clone, Debug, PartialEq)]
6pub enum SyncLevel {
7    One,
8    Infinity,
9}
10
11impl ValueDeserialize for SyncLevel {
12    fn deserialize(val: &str) -> Result<Self, rustical_xml::XmlError> {
13        Ok(match val {
14            "1" => Self::One,
15            "Infinity" => Self::Infinity,
16            _ => {
17                return Err(rustical_xml::XmlError::InvalidValue(
18                    rustical_xml::ParseValueError::Other("Invalid sync-level".to_owned()),
19                ));
20            }
21        })
22    }
23}
24
25impl ValueSerialize for SyncLevel {
26    fn serialize(&self) -> String {
27        match self {
28            SyncLevel::One => "1",
29            SyncLevel::Infinity => "Infinity",
30        }
31        .to_owned()
32    }
33}
34
35// https://datatracker.ietf.org/doc/html/rfc5323#section-5.17
36#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
37pub struct LimitElement {
38    #[xml(ns = "crate::namespace::NS_DAV")]
39    pub nresults: NresultsElement,
40}
41
42impl From<u64> for LimitElement {
43    fn from(value: u64) -> Self {
44        Self {
45            nresults: NresultsElement(value),
46        }
47    }
48}
49
50impl From<LimitElement> for u64 {
51    fn from(value: LimitElement) -> Self {
52        value.nresults.0
53    }
54}
55
56#[derive(XmlDeserialize, Clone, Debug, PartialEq)]
57pub struct NresultsElement(#[xml(ty = "text")] u64);
58
59#[derive(XmlDeserialize, Clone, Debug, PartialEq, XmlRootTag)]
60// <!ELEMENT sync-collection (sync-token, sync-level, limit?, prop)>
61//    <!-- DAV:limit defined in RFC 5323, Section 5.17 -->
62//    <!-- DAV:prop defined in RFC 4918, Section 14.18 -->
63#[xml(ns = "crate::namespace::NS_DAV", root = b"sync-collection")]
64pub struct SyncCollectionRequest<PN: XmlDeserialize> {
65    #[xml(ns = "crate::namespace::NS_DAV")]
66    pub sync_token: String,
67    #[xml(ns = "crate::namespace::NS_DAV")]
68    pub sync_level: SyncLevel,
69    #[xml(ns = "crate::namespace::NS_DAV", ty = "untagged")]
70    pub prop: PropfindType<PN>,
71    #[xml(ns = "crate::namespace::NS_DAV")]
72    pub limit: Option<LimitElement>,
73}
74
75#[cfg(test)]
76mod tests {
77    use crate::xml::{
78        PropElement, PropfindType,
79        sync_collection::{SyncCollectionRequest, SyncLevel},
80    };
81    use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlDocument};
82
83    const SYNC_COLLECTION_REQUEST: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
84    <sync-collection xmlns="DAV:">
85        <sync-token />
86        <sync-level>1</sync-level>
87        <limit>
88            <nresults>100</nresults>
89        </limit>
90        <prop>
91            <getetag />
92        </prop>
93    </sync-collection>
94    "#;
95
96    #[derive(XmlDeserialize, PropName, EnumVariants, PartialEq)]
97    #[xml(unit_variants_ident = "TestPropName")]
98    enum TestProp {
99        Getetag(String),
100    }
101
102    #[test]
103    fn test_parse_sync_collection_request() {
104        let request =
105            SyncCollectionRequest::<TestPropName>::parse_str(SYNC_COLLECTION_REQUEST).unwrap();
106        assert_eq!(
107            request,
108            SyncCollectionRequest {
109                sync_token: "".to_owned(),
110                sync_level: SyncLevel::One,
111                prop: PropfindType::Prop(PropElement(vec![TestPropName::Getetag], vec![])),
112                limit: Some(100.into())
113            }
114        )
115    }
116}