use quick_xml::events::Event; use super::error::ParsingError; use super::synctypes::*; use super::types as dav; use super::xml::{IRead, QRead, Reader, DAV_URN}; impl QRead for PropertyRequest { async fn qread(xml: &mut Reader) -> Result { if xml.maybe_open(DAV_URN, "sync-token").await?.is_some() { xml.close().await?; return Ok(Self::SyncToken); } return Err(ParsingError::Recoverable); } } impl QRead for Property { async fn qread(xml: &mut Reader) -> Result { let mut dirty = false; let mut m_cdr = None; xml.maybe_read(&mut m_cdr, &mut dirty).await?; m_cdr.ok_or(ParsingError::Recoverable).map(Self::SyncToken) } } impl QRead for ReportTypeName { async fn qread(xml: &mut Reader) -> Result { if xml.maybe_open(DAV_URN, "sync-collection").await?.is_some() { xml.close().await?; return Ok(Self::SyncCollection); } Err(ParsingError::Recoverable) } } impl QRead for Multistatus { async fn qread(xml: &mut Reader) -> Result { SyncToken::qread(xml) .await .map(|sync_token| Multistatus { sync_token }) } } impl QRead> for SyncCollection { async fn qread(xml: &mut Reader) -> Result { xml.open(DAV_URN, "sync-collection").await?; let (mut sync_token, mut sync_level, mut limit, mut prop) = (None, None, None, None); loop { let mut dirty = false; xml.maybe_read(&mut sync_token, &mut dirty).await?; xml.maybe_read(&mut sync_level, &mut dirty).await?; xml.maybe_read(&mut limit, &mut dirty).await?; xml.maybe_read(&mut prop, &mut dirty).await?; if !dirty { match xml.peek() { Event::End(_) => break, _ => xml.skip().await?, }; } } xml.close().await?; match (sync_token, sync_level, prop) { (Some(sync_token), Some(sync_level), Some(prop)) => Ok(SyncCollection { sync_token, sync_level, limit, prop, }), _ => Err(ParsingError::MissingChild), } } } impl QRead for SyncTokenRequest { async fn qread(xml: &mut Reader) -> Result { xml.open(DAV_URN, "sync-token").await?; let token = match xml.tag_string().await { Ok(v) => SyncTokenRequest::IncrementalSync(v), Err(ParsingError::Recoverable) => SyncTokenRequest::InitialSync, Err(e) => return Err(e), }; xml.close().await?; Ok(token) } } impl QRead for SyncToken { async fn qread(xml: &mut Reader) -> Result { xml.open(DAV_URN, "sync-token").await?; let token = xml.tag_string().await?; xml.close().await?; Ok(SyncToken(token)) } } impl QRead for SyncLevel { async fn qread(xml: &mut Reader) -> Result { xml.open(DAV_URN, "sync-level").await?; let lvl = match xml.tag_string().await?.to_lowercase().as_str() { "1" => SyncLevel::One, "infinite" => SyncLevel::Infinite, _ => return Err(ParsingError::InvalidValue), }; xml.close().await?; Ok(lvl) } } #[cfg(test)] mod tests { use super::*; use crate::realization::{self, All}; use crate::types as dav; use crate::versioningtypes as vers; use crate::xml::Node; async fn deserialize>(src: &str) -> T { let mut rdr = Reader::new(quick_xml::NsReader::from_reader(src.as_bytes())) .await .unwrap(); rdr.find().await.unwrap() } #[tokio::test] async fn sync_level() { { let expected = SyncLevel::One; let src = r#"1"#; let got = deserialize::(src).await; assert_eq!(got, expected); } { let expected = SyncLevel::Infinite; let src = r#"infinite"#; let got = deserialize::(src).await; assert_eq!(got, expected); } } #[tokio::test] async fn sync_token_request() { { let expected = SyncTokenRequest::InitialSync; let src = r#""#; let got = deserialize::(src).await; assert_eq!(got, expected); } { let expected = SyncTokenRequest::IncrementalSync("http://example.com/ns/sync/1232".into()); let src = r#"http://example.com/ns/sync/1232"#; let got = deserialize::(src).await; assert_eq!(got, expected); } } #[tokio::test] async fn sync_token() { let expected = SyncToken("http://example.com/ns/sync/1232".into()); let src = r#"http://example.com/ns/sync/1232"#; let got = deserialize::(src).await; assert_eq!(got, expected); } #[tokio::test] async fn sync_collection() { { let expected = SyncCollection:: { sync_token: SyncTokenRequest::IncrementalSync( "http://example.com/ns/sync/1232".into(), ), sync_level: SyncLevel::One, limit: Some(vers::Limit(vers::NResults(100))), prop: dav::PropName(vec![dav::PropertyRequest::GetEtag]), }; let src = r#" http://example.com/ns/sync/1232 1 100 "#; let got = deserialize::>(src).await; assert_eq!(got, expected); } { let expected = SyncCollection:: { sync_token: SyncTokenRequest::InitialSync, sync_level: SyncLevel::Infinite, limit: None, prop: dav::PropName(vec![dav::PropertyRequest::GetEtag]), }; let src = r#" infinite "#; let got = deserialize::>(src).await; assert_eq!(got, expected); } } #[tokio::test] async fn prop_req() { let expected = dav::PropName::(vec![dav::PropertyRequest::Extension( realization::PropertyRequest::Sync(PropertyRequest::SyncToken), )]); let src = r#""#; let got = deserialize::>(src).await; assert_eq!(got, expected); } #[tokio::test] async fn prop_val() { let expected = dav::PropValue::(vec![ dav::Property::Extension(realization::Property::Sync(Property::SyncToken(SyncToken( "http://example.com/ns/sync/1232".into(), )))), dav::Property::Extension(realization::Property::Vers( vers::Property::SupportedReportSet(vec![vers::SupportedReport( vers::ReportName::Extension(realization::ReportTypeName::Sync( ReportTypeName::SyncCollection, )), )]), )), ]); let src = r#" http://example.com/ns/sync/1232 "#; let got = deserialize::>(src).await; assert_eq!(got, expected); } }