aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Dufour <quentin@deuxfleurs.fr>2024-03-05 16:07:47 +0100
committerQuentin Dufour <quentin@deuxfleurs.fr>2024-03-05 16:07:47 +0100
commit8e5d8a8aaa7bde2357ca70542a88f744005d58ba (patch)
tree6c6276a296eb5e7b8ec83c7e361247276abc9c61
parentb7a990ecdb0346e12cfeb0de34565f51af61ec80 (diff)
downloadaerogramme-8e5d8a8aaa7bde2357ca70542a88f744005d58ba.tar.gz
aerogramme-8e5d8a8aaa7bde2357ca70542a88f744005d58ba.zip
Refactor encoder+decoder WIP (compile)
-rw-r--r--src/dav/calencoder.rs2
-rw-r--r--src/dav/caltypes.rs32
-rw-r--r--src/dav/decoder.rs132
-rw-r--r--src/dav/encoder.rs616
-rw-r--r--src/dav/error.rs20
-rw-r--r--src/dav/mod.rs3
-rw-r--r--src/dav/realization.rs41
-rw-r--r--src/dav/types.rs138
-rw-r--r--src/dav/xml.rs128
9 files changed, 677 insertions, 435 deletions
diff --git a/src/dav/calencoder.rs b/src/dav/calencoder.rs
index db7ece4..80b8656 100644
--- a/src/dav/calencoder.rs
+++ b/src/dav/calencoder.rs
@@ -1,3 +1,4 @@
+/*
use super::encoder::{QuickWritable, Context};
use super::caltypes::*;
use super::types::Extension;
@@ -893,3 +894,4 @@ mod tests {
assert_eq!(&got, expected, "\n---GOT---\n{got}\n---EXP---\n{expected}\n");
}
}
+*/
diff --git a/src/dav/caltypes.rs b/src/dav/caltypes.rs
index 7131ec2..c8177e9 100644
--- a/src/dav/caltypes.rs
+++ b/src/dav/caltypes.rs
@@ -1,7 +1,8 @@
#![allow(dead_code)]
+/*
use chrono::{DateTime,Utc};
-use super::types as Dav;
+use super::types as dav;
//@FIXME ACL (rfc3744) is missing, required
//@FIXME Versioning (rfc3253) is missing, required
@@ -11,15 +12,6 @@ use super::types as Dav;
// For reference, non-official extensions documented by SabreDAV:
// https://github.com/apple/ccs-calendarserver/tree/master/doc/Extensions
-pub struct CalExtension {
- pub root: bool
-}
-impl Dav::Extension for CalExtension {
- type Error = Violation;
- type Property = Property;
- type PropertyRequest = PropertyRequest;
- type ResourceType = ResourceType;
-}
// ----- Root elements -----
@@ -35,7 +27,7 @@ impl Dav::Extension for CalExtension {
/// instruction in Section 12.13.2 of [RFC2518].
///
/// <!ELEMENT mkcalendar (DAV:set)>
-pub struct MkCalendar<E: Dav::Extension>(pub Dav::Set<E>);
+pub struct MkCalendar<E: dav::Extension>(pub dav::Set<E>);
/// If a response body for a successful request is included, it MUST
@@ -51,7 +43,7 @@ pub struct MkCalendar<E: Dav::Extension>(pub Dav::Set<E>);
/// Definition:
///
/// <!ELEMENT mkcol-response (propstat+)>
-pub struct MkCalendarResponse<T: Dav::Extension>(pub Vec<Dav::PropStat<T>>);
+pub struct MkCalendarResponse<E: dav::Extension>(pub Vec<dav::PropStat<E>>);
// --- (REPORT PART) ---
@@ -68,8 +60,8 @@ pub struct MkCalendarResponse<T: Dav::Extension>(pub Vec<Dav::PropStat<T>>);
/// <!ELEMENT calendar-query ((DAV:allprop |
/// DAV:propname |
/// DAV:prop)?, filter, timezone?)>
-pub struct CalendarQuery<T: Dav::Extension> {
- pub selector: Option<CalendarSelector<T>>,
+pub struct CalendarQuery<E: dav::Extension> {
+ pub selector: Option<CalendarSelector<E>>,
pub filter: Filter,
pub timezone: Option<TimeZone>,
}
@@ -88,9 +80,9 @@ pub struct CalendarQuery<T: Dav::Extension> {
/// <!ELEMENT calendar-multiget ((DAV:allprop |
/// DAV:propname |
/// DAV:prop)?, DAV:href+)>
-pub struct CalendarMultiget<T: Dav::Extension> {
- pub selector: Option<CalendarSelector<T>>,
- pub href: Vec<Dav::Href>,
+pub struct CalendarMultiget<E: dav::Extension> {
+ pub selector: Option<CalendarSelector<E>>,
+ pub href: Vec<dav::Href>,
}
/// Name: free-busy-query
@@ -1056,10 +1048,10 @@ pub struct LimitRecurrenceSet(pub DateTime<Utc>, pub DateTime<Utc>);
pub struct LimitFreebusySet(pub DateTime<Utc>, pub DateTime<Utc>);
/// Used by CalendarQuery & CalendarMultiget
-pub enum CalendarSelector<T: Dav::Extension> {
+pub enum CalendarSelector<E: dav::Extension> {
AllProp,
PropName,
- Prop(Dav::PropName<T>),
+ Prop(dav::PropName<E>),
}
/// Name: comp-filter
@@ -1402,4 +1394,4 @@ impl Collation {
Self::Unknown(c) => c.as_str(),
}
}
-}
+}*/
diff --git a/src/dav/decoder.rs b/src/dav/decoder.rs
index 719ea8c..1756464 100644
--- a/src/dav/decoder.rs
+++ b/src/dav/decoder.rs
@@ -8,33 +8,32 @@ use quick_xml::reader::NsReader;
use tokio::io::AsyncBufRead;
use super::types::*;
+use super::error::*;
-#[derive(Debug)]
-pub enum ParsingError {
- NamespacePrefixAlreadyUsed,
- WrongToken,
- TagNotFound,
- QuickXml(quick_xml::Error),
- Eof
+/*
+// --- Traits ----
+
+trait Reader = AsyncBufRead+Unpin+'static;
+
+trait Decodable: Extension {
+ async fn decode_propreq(xml: &mut PeekRead<impl Reader>) -> Result<Option<Self::PropertyRequest>, ParsingError>;
}
-impl From<AttrError> for ParsingError {
- fn from(value: AttrError) -> Self {
- Self::QuickXml(value.into())
+impl Decodable for NoExtension {
+ async fn decode_propreq(xml: &mut PeekRead<impl Reader>) -> Result<Option<Disabled>, ParsingError> {
+ Ok(None)
}
}
-impl From<quick_xml::Error> for ParsingError {
- fn from(value: quick_xml::Error) -> Self {
- Self::QuickXml(value)
- }
+
+pub trait QReadable<T: Reader>: Sized {
+ async fn read(xml: &mut PeekRead<T>) -> Result<Self, ParsingError>;
}
+// --- Peek read with namespaces
+
const DAV_URN: &[u8] = b"DAV:";
const CALDAV_URN: &[u8] = b"urn:ietf:params:xml:ns:caldav";
const CARDDAV_URN: &[u8] = b"urn:ietf:params:xml:ns:carddav";
//const XML_URN: &[u8] = b"xml";
-
-trait Reader = AsyncBufRead+Unpin+'static;
-
pub struct PeekRead<T: Reader> {
evt: Event<'static>,
rdr: NsReader<T>,
@@ -117,11 +116,9 @@ impl<T: Reader> PeekRead<T> {
}
}
-pub trait QReadable<T: Reader>: Sized {
- async fn read(xml: &mut PeekRead<T>) -> Result<Self, ParsingError>;
-}
+// ----- Decode ----
-impl<E: Extension, T: Reader> QReadable<T> for PropFind<E> {
+impl<E: Decodable, T: Reader> QReadable<T> for PropFind<E> {
async fn read(xml: &mut PeekRead<T>) -> Result<PropFind<E>, ParsingError> {
// Find propfind
xml.tag_start(DAV_URN, "propfind").await?;
@@ -161,13 +158,13 @@ impl<E: Extension, T: Reader> QReadable<T> for PropFind<E> {
}
-impl<E: Extension, T: Reader> QReadable<T> for Include<E> {
+impl<E: Decodable, T: Reader> QReadable<T> for Include<E> {
async fn read(xml: &mut PeekRead<T>) -> Result<Include<E>, ParsingError> {
xml.tag_start(DAV_URN, "include").await?;
let mut acc: Vec<PropertyRequest<E>> = Vec::new();
loop {
match xml.peek() {
- Event::Start(_) => acc.push(PropertyRequest::read(xml).await?),
+ Event::Start(_) | Event::Empty(_) => acc.push(PropertyRequest::read(xml).await?),
Event::End(_) if xml.is_tag(DAV_URN, "include") => break,
_ => { xml.skip().await?; },
}
@@ -177,13 +174,13 @@ impl<E: Extension, T: Reader> QReadable<T> for Include<E> {
}
}
-impl<E: Extension, T: Reader> QReadable<T> for PropName<E> {
+impl<E: Decodable, T: Reader> QReadable<T> for PropName<E> {
async fn read(xml: &mut PeekRead<T>) -> Result<PropName<E>, ParsingError> {
xml.tag_start(DAV_URN, "prop").await?;
let mut acc: Vec<PropertyRequest<E>> = Vec::new();
loop {
match xml.peek() {
- Event::Start(_) => acc.push(PropertyRequest::read(xml).await?),
+ Event::Start(_) | Event::Empty(_) => acc.push(PropertyRequest::read(xml).await?),
Event::End(_) if xml.is_tag(DAV_URN, "prop") => break,
_ => { xml.skip().await?; },
}
@@ -193,12 +190,52 @@ impl<E: Extension, T: Reader> QReadable<T> for PropName<E> {
}
}
-impl<E: Extension, T: Reader> QReadable<T> for PropertyRequest<E> {
+impl<E: Decodable, T: Reader> QReadable<T> for PropertyRequest<E> {
async fn read(xml: &mut PeekRead<T>) -> Result<PropertyRequest<E>, ParsingError> {
- /*match xml.peek() {
-
- }*/
- unimplemented!();
+ loop {
+ let (need_close, bs) = match xml.peek() {
+ Event::Start(b) => (true, b),
+ Event::Empty(b) => (false, b),
+ _ => {
+ xml.skip().await?;
+ continue
+ },
+ };
+
+ let mut maybe_res = None;
+
+ // Option 1: a pure DAV property
+ let (ns, loc) = xml.rdr.resolve_element(bs.name());
+ if matches!(ns, Bound(Namespace(ns)) if ns == DAV_URN) {
+ maybe_res = match loc.into_inner() {
+ b"creationdate" => Some(PropertyRequest::CreationDate),
+ b"displayname" => Some(PropertyRequest::DisplayName),
+ b"getcontentlanguage" => Some(PropertyRequest::GetContentLanguage),
+ b"getcontentlength" => Some(PropertyRequest::GetContentLength),
+ b"getetag" => Some(PropertyRequest::GetEtag),
+ b"getlastmodified" => Some(PropertyRequest::GetLastModified),
+ b"lockdiscovery" => Some(PropertyRequest::LockDiscovery),
+ b"resourcetype" => Some(PropertyRequest::ResourceType),
+ b"supportedlock" => Some(PropertyRequest::SupportedLock),
+ _ => None,
+ };
+ }
+
+ // Option 2: an extension property
+ if maybe_res.is_none() {
+ maybe_res = E::decode_propreq(xml).await?.map(PropertyRequest::Extension);
+ }
+
+ // In any cases, we must close the opened tag
+ if need_close {
+ xml.skip().await?;
+ }
+
+ // Return if something is found - otherwise loop
+ if let Some(res) = maybe_res {
+ return Ok(res)
+ }
+ }
}
}
@@ -207,7 +244,7 @@ mod tests {
use super::*;
#[tokio::test]
- async fn basic_propfind() {
+ async fn basic_propfind_propname() {
let src = r#"<?xml version="1.0" encoding="utf-8" ?>
<rando/>
<garbage><old/></garbage>
@@ -220,4 +257,37 @@ mod tests {
let got = PropFind::<NoExtension>::read(&mut rdr).await.unwrap();
assert!(matches!(got, PropFind::PropName));
}
+/*
+ #[tokio::test]
+ async fn basic_propfind_prop() {
+ let src = r#"<?xml version="1.0" encoding="utf-8" ?>
+<rando/>
+<garbage><old/></garbage>
+<D:propfind xmlns:D="DAV:">
+ <D:prop>
+ <displayname/>
+ <getcontentlength/>
+ <getcontenttype/>
+ <getetag/>
+ <getlastmodified/>
+ <resourcetype/>
+ <supportedlock/>
+ </D:prop>
+</D:propfind>
+"#;
+
+ let mut rdr = PeekRead::new(NsReader::from_reader(src.as_bytes())).await.unwrap();
+ let got = PropFind::<NoExtension>::read(&mut rdr).await.unwrap();
+ assert_eq!(got, PropFind::Prop(PropName(vec![
+ PropertyRequest::DisplayName,
+ PropertyRequest::GetContentLength,
+ PropertyRequest::GetContentType,
+ PropertyRequest::GetEtag,
+ PropertyRequest::GetLastModified,
+ PropertyRequest::ResourceType,
+ PropertyRequest::SupportedLock,
+ ])));
+ }
+ */
}
+*/
diff --git a/src/dav/encoder.rs b/src/dav/encoder.rs
index 7778d61..745c396 100644
--- a/src/dav/encoder.rs
+++ b/src/dav/encoder.rs
@@ -2,390 +2,339 @@ use std::io::Cursor;
use quick_xml::Error as QError;
use quick_xml::events::{Event, BytesEnd, BytesStart, BytesText};
-use quick_xml::writer::{ElementWriter, Writer};
+use quick_xml::writer::ElementWriter;
use quick_xml::name::PrefixDeclaration;
use tokio::io::AsyncWrite;
use super::types::*;
+use super::xml::{Writer,QWrite,IWrite};
-//-------------- TRAITS ----------------------
-
-/// Basic encode trait to make a type encodable
-pub trait QuickWritable<C: Context> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError>;
-}
-
-/// Encoding context
-pub trait Context: Extension {
- fn child(&self) -> Self;
- fn create_dav_element(&self, name: &str) -> BytesStart;
- async fn hook_error(&self, err: &Self::Error, xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError>;
- async fn hook_property(&self, prop: &Self::Property, xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError>;
- async fn hook_propertyrequest(&self, prop: &Self::PropertyRequest, xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError>;
- async fn hook_resourcetype(&self, prop: &Self::ResourceType, xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError>;
-}
-
-/// -------------- NoExtension Encoding Context
-impl Context for NoExtension {
- fn child(&self) -> Self {
- Self { root: false }
- }
- fn create_dav_element(&self, name: &str) -> BytesStart {
- let mut start = BytesStart::new(format!("D:{}", name));
- if self.root {
- start.push_attribute(("xmlns:D", "DAV:"));
- }
- start
- }
- async fn hook_error(&self, _err: &Disabled, _xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError> {
- unreachable!();
- }
- async fn hook_property(&self, _prop: &Disabled, _xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError> {
- unreachable!();
- }
- async fn hook_propertyrequest(&self, _prop: &Disabled, _xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError> {
- unreachable!();
- }
- async fn hook_resourcetype(&self, _restype: &Disabled, _xml: &mut Writer<impl AsyncWrite+Unpin>) -> Result<(), QError> {
- unreachable!();
- }
-}
-
-
-//--------------------- ENCODING --------------------
-
// --- XML ROOTS
/// PROPFIND REQUEST
-impl<C: Context> QuickWritable<C> for PropFind<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("propfind");
+impl<E: Extension> QWrite for PropFind<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("propfind");
let end = start.to_end();
- let ctx = ctx.child();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
match self {
- Self::PropName => xml.write_event_async(Event::Empty(ctx.create_dav_element("propname"))).await?,
+ Self::PropName => {
+ let empty_propname = xml.create_dav_element("propname");
+ xml.q.write_event_async(Event::Empty(empty_propname)).await?
+ },
Self::AllProp(maybe_include) => {
- xml.write_event_async(Event::Empty(ctx.create_dav_element("allprop"))).await?;
+ let empty_allprop = xml.create_dav_element("allprop");
+ xml.q.write_event_async(Event::Empty(empty_allprop)).await?;
if let Some(include) = maybe_include {
- include.write(xml, ctx.child()).await?;
+ include.qwrite(xml).await?;
}
},
- Self::Prop(propname) => propname.write(xml, ctx.child()).await?,
+ Self::Prop(propname) => propname.qwrite(xml).await?,
}
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::End(end)).await
}
}
/// PROPPATCH REQUEST
-impl<C: Context> QuickWritable<C> for PropertyUpdate<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("propertyupdate");
+impl<E: Extension> QWrite for PropertyUpdate<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("propertyupdate");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
for update in self.0.iter() {
- update.write(xml, ctx.child()).await?;
+ update.qwrite(xml).await?;
}
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::End(end)).await
}
}
/// PROPFIND RESPONSE, PROPPATCH RESPONSE, COPY RESPONSE, MOVE RESPONSE
/// DELETE RESPONSE,
-impl<C: Context> QuickWritable<C> for Multistatus<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("multistatus");
+impl<E: Extension> QWrite for Multistatus<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("multistatus");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
for response in self.responses.iter() {
- response.write(xml, ctx.child()).await?;
+ response.qwrite(xml).await?;
}
if let Some(description) = &self.responsedescription {
- description.write(xml, ctx.child()).await?;
+ description.qwrite(xml).await?;
}
- xml.write_event_async(Event::End(end)).await?;
+ xml.q.write_event_async(Event::End(end)).await?;
Ok(())
}
}
/// LOCK REQUEST
-impl<C: Context> QuickWritable<C> for LockInfo {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("lockinfo");
+impl QWrite for LockInfo {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("lockinfo");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- self.lockscope.write(xml, ctx.child()).await?;
- self.locktype.write(xml, ctx.child()).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ self.lockscope.qwrite(xml).await?;
+ self.locktype.qwrite(xml).await?;
if let Some(owner) = &self.owner {
- owner.write(xml, ctx.child()).await?;
+ owner.qwrite(xml).await?;
}
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::End(end)).await
}
}
/// SOME LOCK RESPONSES
-impl<C: Context> QuickWritable<C> for PropValue<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("prop");
+impl<E: Extension> QWrite for PropValue<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("prop");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
for propval in &self.0 {
- propval.write(xml, ctx.child()).await?;
+ propval.qwrite(xml).await?;
}
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::End(end)).await
}
}
// --- XML inner elements
-impl<C: Context> QuickWritable<C> for PropertyUpdateItem<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
+impl<E: Extension> QWrite for PropertyUpdateItem<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
match self {
- Self::Set(set) => set.write(xml, ctx).await,
- Self::Remove(rm) => rm.write(xml, ctx).await,
+ Self::Set(set) => set.qwrite(xml).await,
+ Self::Remove(rm) => rm.qwrite(xml).await,
}
}
}
-impl<C: Context> QuickWritable<C> for Set<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("set");
+impl<E: Extension> QWrite for Set<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("set");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- self.0.write(xml, ctx.child()).await?;
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ self.0.qwrite(xml).await?;
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for Remove<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("remove");
+impl<E: Extension> QWrite for Remove<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("remove");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- self.0.write(xml, ctx.child()).await?;
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ self.0.qwrite(xml).await?;
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for AnyProp<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
+impl<E: Extension> QWrite for AnyProp<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
match self {
- Self::Name(propname) => propname.write(xml, ctx).await,
- Self::Value(propval) => propval.write(xml, ctx).await,
+ Self::Name(propname) => propname.qwrite(xml).await,
+ Self::Value(propval) => propval.qwrite(xml).await,
}
}
}
-impl<C: Context> QuickWritable<C> for PropName<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("prop");
+impl<E: Extension> QWrite for PropName<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("prop");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
for propname in &self.0 {
- propname.write(xml, ctx.child()).await?;
+ propname.qwrite(xml).await?;
}
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for Href {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("href");
+impl QWrite for Href {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("href");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- xml.write_event_async(Event::Text(BytesText::new(&self.0))).await?;
- xml.write_event_async(Event::End(end)).await?;
-
- Ok(())
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Text(BytesText::new(&self.0))).await?;
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for Response<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("response");
+impl<E: Extension> QWrite for Response<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("response");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- self.href.write(xml, ctx.child()).await?;
- self.status_or_propstat.write(xml, ctx.child()).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ self.href.qwrite(xml).await?;
+ self.status_or_propstat.qwrite(xml).await?;
if let Some(error) = &self.error {
- error.write(xml, ctx.child()).await?;
+ error.qwrite(xml).await?;
}
if let Some(responsedescription) = &self.responsedescription {
- responsedescription.write(xml, ctx.child()).await?;
+ responsedescription.qwrite(xml).await?;
}
if let Some(location) = &self.location {
- location.write(xml, ctx.child()).await?;
+ location.qwrite(xml).await?;
}
- xml.write_event_async(Event::End(end)).await?;
-
- Ok(())
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for StatusOrPropstat<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
+impl<E: Extension> QWrite for StatusOrPropstat<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
match self {
- Self::Status(status) => status.write(xml, ctx.child()).await,
+ Self::Status(status) => status.qwrite(xml).await,
Self::PropStat(propstat_list) => {
for propstat in propstat_list.iter() {
- propstat.write(xml, ctx.child()).await?;
+ propstat.qwrite(xml).await?;
}
-
Ok(())
}
}
}
}
-impl<C: Context> QuickWritable<C> for Status {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("status");
+impl QWrite for Status {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("status");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
let txt = format!("HTTP/1.1 {} {}", self.0.as_str(), self.0.canonical_reason().unwrap_or("No reason"));
- xml.write_event_async(Event::Text(BytesText::new(&txt))).await?;
+ xml.q.write_event_async(Event::Text(BytesText::new(&txt))).await?;
- xml.write_event_async(Event::End(end)).await?;
+ xml.q.write_event_async(Event::End(end)).await?;
Ok(())
}
}
-impl<C: Context> QuickWritable<C> for ResponseDescription {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("responsedescription");
+impl QWrite for ResponseDescription {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("responsedescription");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- xml.write_event_async(Event::Text(BytesText::new(&self.0))).await?;
- xml.write_event_async(Event::End(end)).await?;
-
- Ok(())
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Text(BytesText::new(&self.0))).await?;
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for Location {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("location");
+impl QWrite for Location {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("location");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- self.0.write(xml, ctx.child()).await?;
- xml.write_event_async(Event::End(end)).await?;
-
- Ok(())
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ self.0.qwrite(xml).await?;
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for PropStat<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("propstat");
+impl<E: Extension> QWrite for PropStat<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("propstat");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- self.prop.write(xml, ctx.child()).await?;
- self.status.write(xml, ctx.child()).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ self.prop.qwrite(xml).await?;
+ self.status.qwrite(xml).await?;
if let Some(error) = &self.error {
- error.write(xml, ctx.child()).await?;
+ error.qwrite(xml).await?;
}
if let Some(description) = &self.responsedescription {
- description.write(xml, ctx.child()).await?;
+ description.qwrite(xml).await?;
}
- xml.write_event_async(Event::End(end)).await?;
+ xml.q.write_event_async(Event::End(end)).await?;
Ok(())
}
}
-impl<C: Context> QuickWritable<C> for Property<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
+impl<E: Extension> QWrite for Property<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
use Property::*;
match self {
CreationDate(date) => {
// <D:creationdate>1997-12-01T17:42:21-08:00</D:creationdate>
- let start = ctx.create_dav_element("creationdate");
+ let start = xml.create_dav_element("creationdate");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- xml.write_event_async(Event::Text(BytesText::new(&date.to_rfc3339()))).await?;
- xml.write_event_async(Event::End(end)).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Text(BytesText::new(&date.to_rfc3339()))).await?;
+ xml.q.write_event_async(Event::End(end)).await?;
},
DisplayName(name) => {
// <D:displayname>Example collection</D:displayname>
- let start = ctx.create_dav_element("displayname");
+ let start = xml.create_dav_element("displayname");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- xml.write_event_async(Event::Text(BytesText::new(name))).await?;
- xml.write_event_async(Event::End(end)).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Text(BytesText::new(name))).await?;
+ xml.q.write_event_async(Event::End(end)).await?;
},
GetContentLanguage(lang) => {
- let start = ctx.create_dav_element("getcontentlanguage");
+ let start = xml.create_dav_element("getcontentlanguage");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- xml.write_event_async(Event::Text(BytesText::new(lang))).await?;
- xml.write_event_async(Event::End(end)).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Text(BytesText::new(lang))).await?;
+ xml.q.write_event_async(Event::End(end)).await?;
},
GetContentLength(len) => {
// <D:getcontentlength>4525</D:getcontentlength>
- let start = ctx.create_dav_element("getcontentlength");
+ let start = xml.create_dav_element("getcontentlength");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- xml.write_event_async(Event::Text(BytesText::new(&len.to_string()))).await?;
- xml.write_event_async(Event::End(end)).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Text(BytesText::new(&len.to_string()))).await?;
+ xml.q.write_event_async(Event::End(end)).await?;
},
GetContentType(ct) => {
// <D:getcontenttype>text/html</D:getcontenttype>
- let start = ctx.create_dav_element("getcontenttype");
+ let start = xml.create_dav_element("getcontenttype");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- xml.write_event_async(Event::Text(BytesText::new(&ct))).await?;
- xml.write_event_async(Event::End(end)).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Text(BytesText::new(&ct))).await?;
+ xml.q.write_event_async(Event::End(end)).await?;
},
GetEtag(et) => {
// <D:getetag>"zzyzx"</D:getetag>
- let start = ctx.create_dav_element("getetag");
+ let start = xml.create_dav_element("getetag");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- xml.write_event_async(Event::Text(BytesText::new(et))).await?;
- xml.write_event_async(Event::End(end)).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Text(BytesText::new(et))).await?;
+ xml.q.write_event_async(Event::End(end)).await?;
},
GetLastModified(date) => {
// <D:getlastmodified>Mon, 12 Jan 1998 09:25:56 GMT</D:getlastmodified>
- let start = ctx.create_dav_element("getlastmodified");
+ let start = xml.create_dav_element("getlastmodified");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- xml.write_event_async(Event::Text(BytesText::new(&date.to_rfc2822()))).await?;
- xml.write_event_async(Event::End(end)).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Text(BytesText::new(&date.to_rfc2822()))).await?;
+ xml.q.write_event_async(Event::End(end)).await?;
},
LockDiscovery(many_locks) => {
// <D:lockdiscovery><D:activelock> ... </D:activelock></D:lockdiscovery>
- let start = ctx.create_dav_element("lockdiscovery");
+ let start = xml.create_dav_element("lockdiscovery");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
for lock in many_locks.iter() {
- lock.write(xml, ctx.child()).await?;
+ lock.qwrite(xml).await?;
}
- xml.write_event_async(Event::End(end)).await?;
+ xml.q.write_event_async(Event::End(end)).await?;
},
ResourceType(many_types) => {
// <D:resourcetype><D:collection/></D:resourcetype>
@@ -397,16 +346,16 @@ impl<C: Context> QuickWritable<C> for Property<C> {
// <f:search-results xmlns:f="http://www.example.com/ns"/>
// </x:resourcetype>
- let start = ctx.create_dav_element("resourcetype");
+ let start = xml.create_dav_element("resourcetype");
if many_types.is_empty() {
- xml.write_event_async(Event::Empty(start)).await?;
+ xml.q.write_event_async(Event::Empty(start)).await?;
} else {
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
for restype in many_types.iter() {
- restype.write(xml, ctx.child()).await?;
+ restype.qwrite(xml).await?;
}
- xml.write_event_async(Event::End(end)).await?;
+ xml.q.write_event_async(Event::End(end)).await?;
}
},
SupportedLock(many_entries) => {
@@ -414,52 +363,56 @@ impl<C: Context> QuickWritable<C> for Property<C> {
// <D:supportedlock> <D:lockentry> ... </D:lockentry> </D:supportedlock>
- let start = ctx.create_dav_element("supportedlock");
+ let start = xml.create_dav_element("supportedlock");
if many_entries.is_empty() {
- xml.write_event_async(Event::Empty(start)).await?;
+ xml.q.write_event_async(Event::Empty(start)).await?;
} else {
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
for entry in many_entries.iter() {
- entry.write(xml, ctx.child()).await?;
+ entry.qwrite(xml).await?;
}
- xml.write_event_async(Event::End(end)).await?;
+ xml.q.write_event_async(Event::End(end)).await?;
}
},
- Extension(inner) => {
- ctx.hook_property(inner, xml).await?;
- },
+ Extension(inner) => inner.qwrite(xml).await?,
};
Ok(())
}
}
-impl<C: Context> QuickWritable<C> for ResourceType<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
+impl<E: Extension> QWrite for ResourceType<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
match self {
- Self::Collection => xml.write_event_async(Event::Empty(ctx.create_dav_element("collection"))).await,
- Self::Extension(inner) => ctx.hook_resourcetype(inner, xml).await,
+ Self::Collection => {
+ let empty_collection = xml.create_dav_element("collection");
+ xml.q.write_event_async(Event::Empty(empty_collection)).await
+ },
+ Self::Extension(inner) => inner.qwrite(xml).await,
}
}
}
-impl<C: Context> QuickWritable<C> for Include<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("include");
+impl<E: Extension> QWrite for Include<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("include");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
for prop in self.0.iter() {
- prop.write(xml, ctx.child()).await?;
+ prop.qwrite(xml).await?;
}
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for PropertyRequest<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
+impl<E: Extension> QWrite for PropertyRequest<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
use PropertyRequest::*;
- let mut atom = async |c| xml.write_event_async(Event::Empty(ctx.create_dav_element(c))).await;
+ let mut atom = async |c| {
+ let empty_tag = xml.create_dav_element(c);
+ xml.q.write_event_async(Event::Empty(empty_tag)).await
+ };
match self {
CreationDate => atom("creationdate").await,
@@ -472,13 +425,13 @@ impl<C: Context> QuickWritable<C> for PropertyRequest<C> {
LockDiscovery => atom("lockdiscovery").await,
ResourceType => atom("resourcetype").await,
SupportedLock => atom("supportedlock").await,
- Extension(inner) => ctx.hook_propertyrequest(inner, xml).await,
+ Extension(inner) => inner.qwrite(xml).await,
}
}
}
-impl<C: Context> QuickWritable<C> for ActiveLock {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
+impl QWrite for ActiveLock {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
// <D:activelock>
// <D:locktype><D:write/></D:locktype>
// <D:lockscope><D:exclusive/></D:lockscope>
@@ -494,192 +447,193 @@ impl<C: Context> QuickWritable<C> for ActiveLock {
// <D:href>http://example.com/workspace/webdav/proposal.doc</D:href>
// </D:lockroot>
// </D:activelock>
- let start = ctx.create_dav_element("activelock");
+ let start = xml.create_dav_element("activelock");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- self.locktype.write(xml, ctx.child()).await?;
- self.lockscope.write(xml, ctx.child()).await?;
- self.depth.write(xml, ctx.child()).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ self.locktype.qwrite(xml).await?;
+ self.lockscope.qwrite(xml).await?;
+ self.depth.qwrite(xml).await?;
if let Some(owner) = &self.owner {
- owner.write(xml, ctx.child()).await?;
+ owner.qwrite(xml).await?;
}
if let Some(timeout) = &self.timeout {
- timeout.write(xml, ctx.child()).await?;
+ timeout.qwrite(xml).await?;
}
if let Some(locktoken) = &self.locktoken {
- locktoken.write(xml, ctx.child()).await?;
+ locktoken.qwrite(xml).await?;
}
- self.lockroot.write(xml, ctx.child()).await?;
- xml.write_event_async(Event::End(end)).await?;
-
- Ok(())
+ self.lockroot.qwrite(xml).await?;
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for LockType {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("locktype");
+impl QWrite for LockType {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("locktype");
let end = start.to_end();
- let ctx = ctx.child();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
match self {
- Self::Write => xml.write_event_async(Event::Empty(ctx.create_dav_element("write"))).await?,
+ Self::Write => {
+ let empty_write = xml.create_dav_element("write");
+ xml.q.write_event_async(Event::Empty(empty_write)).await?
+ },
};
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for LockScope {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("lockscope");
+impl QWrite for LockScope {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("lockscope");
let end = start.to_end();
- let ctx = ctx.child();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
match self {
- Self::Exclusive => xml.write_event_async(Event::Empty(ctx.create_dav_element("exclusive"))).await?,
- Self::Shared => xml.write_event_async(Event::Empty(ctx.create_dav_element("shared"))).await?,
+ Self::Exclusive => {
+ let empty_tag = xml.create_dav_element("exclusive");
+ xml.q.write_event_async(Event::Empty(empty_tag)).await?
+ },
+ Self::Shared => {
+ let empty_tag = xml.create_dav_element("shared");
+ xml.q.write_event_async(Event::Empty(empty_tag)).await?
+ },
};
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for Owner {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("owner");
+impl QWrite for Owner {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("owner");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
match self {
- Self::Txt(txt) => xml.write_event_async(Event::Text(BytesText::new(&txt))).await?,
- Self::Href(href) => href.write(xml, ctx.child()).await?,
+ Self::Txt(txt) => xml.q.write_event_async(Event::Text(BytesText::new(&txt))).await?,
+ Self::Href(href) => href.qwrite(xml).await?,
}
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for Depth {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("depth");
+impl QWrite for Depth {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("depth");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
match self {
- Self::Zero => xml.write_event_async(Event::Text(BytesText::new("0"))).await?,
- Self::One => xml.write_event_async(Event::Text(BytesText::new("1"))).await?,
- Self::Infinity => xml.write_event_async(Event::Text(BytesText::new("infinity"))).await?,
+ Self::Zero => xml.q.write_event_async(Event::Text(BytesText::new("0"))).await?,
+ Self::One => xml.q.write_event_async(Event::Text(BytesText::new("1"))).await?,
+ Self::Infinity => xml.q.write_event_async(Event::Text(BytesText::new("infinity"))).await?,
};
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for Timeout {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("timeout");
+impl QWrite for Timeout {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("timeout");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
match self {
Self::Seconds(count) => {
let txt = format!("Second-{}", count);
- xml.write_event_async(Event::Text(BytesText::new(&txt))).await?
+ xml.q.write_event_async(Event::Text(BytesText::new(&txt))).await?
},
- Self::Infinite => xml.write_event_async(Event::Text(BytesText::new("Infinite"))).await?
+ Self::Infinite => xml.q.write_event_async(Event::Text(BytesText::new("Infinite"))).await?
};
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for LockToken {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("locktoken");
+impl QWrite for LockToken {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("locktoken");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- self.0.write(xml, ctx.child()).await?;
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ self.0.qwrite(xml).await?;
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for LockRoot {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("lockroot");
+impl QWrite for LockRoot {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("lockroot");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- self.0.write(xml, ctx.child()).await?;
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ self.0.qwrite(xml).await?;
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for LockEntry {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("lockentry");
+impl QWrite for LockEntry {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("lockentry");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
- self.lockscope.write(xml, ctx.child()).await?;
- self.locktype.write(xml, ctx.child()).await?;
- xml.write_event_async(Event::End(end)).await
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
+ self.lockscope.qwrite(xml).await?;
+ self.locktype.qwrite(xml).await?;
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for Error<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
- let start = ctx.create_dav_element("error");
+impl<E: Extension> QWrite for Error<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let start = xml.create_dav_element("error");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
for violation in &self.0 {
- violation.write(xml, ctx.child()).await?;
+ violation.qwrite(xml).await?;
}
- xml.write_event_async(Event::End(end)).await?;
-
- Ok(())
+ xml.q.write_event_async(Event::End(end)).await
}
}
-impl<C: Context> QuickWritable<C> for Violation<C> {
- async fn write(&self, xml: &mut Writer<impl AsyncWrite+Unpin>, ctx: C) -> Result<(), QError> {
+impl<E: Extension> QWrite for Violation<E> {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), QError> {
+ let mut atom = async |c| {
+ let empty_tag = xml.create_dav_element(c);
+ xml.q.write_event_async(Event::Empty(empty_tag)).await
+ };
+
match self {
- Violation::LockTokenMatchesRequestUri => xml.write_event_async(Event::Empty(ctx.create_dav_element("lock-token-matches-request-uri"))).await?,
- Violation::LockTokenSubmitted(hrefs) if hrefs.is_empty() => {
- xml.write_event_async(Event::Empty(ctx.create_dav_element("lock-token-submitted"))).await?
- },
+ Violation::LockTokenMatchesRequestUri => atom("lock-token-matches-request-uri").await,
+ Violation::LockTokenSubmitted(hrefs) if hrefs.is_empty() => atom("lock-token-submitted").await,
Violation::LockTokenSubmitted(hrefs) => {
- let start = ctx.create_dav_element("lock-token-submitted");
+ let start = xml.create_dav_element("lock-token-submitted");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
for href in hrefs {
- href.write(xml, ctx.child()).await?;
+ href.qwrite(xml).await?;
}
- xml.write_event_async(Event::End(end)).await?;
- },
- Violation::NoConflictingLock(hrefs) if hrefs.is_empty() => {
- xml.write_event_async(Event::Empty(ctx.create_dav_element("no-conflicting-lock"))).await?
+ xml.q.write_event_async(Event::End(end)).await
},
+ Violation::NoConflictingLock(hrefs) if hrefs.is_empty() => atom("no-conflicting-lock").await,
Violation::NoConflictingLock(hrefs) => {
- let start = ctx.create_dav_element("no-conflicting-lock");
+ let start = xml.create_dav_element("no-conflicting-lock");
let end = start.to_end();
- xml.write_event_async(Event::Start(start.clone())).await?;
+ xml.q.write_event_async(Event::Start(start.clone())).await?;
for href in hrefs {
- href.write(xml, ctx.child()).await?;
+ href.qwrite(xml).await?;
}
- xml.write_event_async(Event::End(end)).await?;
- },
- Violation::NoExternalEntities => xml.write_event_async(Event::Empty(ctx.create_dav_element("no-external-entities"))).await?,
- Violation::PreservedLiveProperties => xml.write_event_async(Event::Empty(ctx.create_dav_element("preserved-live-properties"))).await?,
- Violation::PropfindFiniteDepth => xml.write_event_async(Event::Empty(ctx.create_dav_element("propfind-finite-depth"))).await?,
- Violation::CannotModifyProtectedProperty => xml.write_event_async(Event::Empty(ctx.create_dav_element("cannot-modify-protected-property"))).await?,
- Violation::Extension(inner) => {
- ctx.hook_error(inner, xml).await?;
+ xml.q.write_event_async(Event::End(end)).await
},
- };
- Ok(())
+ Violation::NoExternalEntities => atom("no-external-entities").await,
+ Violation::PreservedLiveProperties => atom("preserved-live-properties").await,
+ Violation::PropfindFiniteDepth => atom("propfind-finite-depth").await,
+ Violation::CannotModifyProtectedProperty => atom("cannot-modify-protected-property").await,
+ Violation::Extension(inner) => inner.qwrite(xml).await,
+ }
}
}
diff --git a/src/dav/error.rs b/src/dav/error.rs
new file mode 100644
index 0000000..1db2895
--- /dev/null
+++ b/src/dav/error.rs
@@ -0,0 +1,20 @@
+use quick_xml::events::attributes::AttrError;
+
+#[derive(Debug)]
+pub enum ParsingError {
+ NamespacePrefixAlreadyUsed,
+ WrongToken,
+ TagNotFound,
+ QuickXml(quick_xml::Error),
+ Eof
+}
+impl From<AttrError> for ParsingError {
+ fn from(value: AttrError) -> Self {
+ Self::QuickXml(value.into())
+ }
+}
+impl From<quick_xml::Error> for ParsingError {
+ fn from(value: quick_xml::Error) -> Self {
+ Self::QuickXml(value)
+ }
+}
diff --git a/src/dav/mod.rs b/src/dav/mod.rs
index 835544b..abc46e7 100644
--- a/src/dav/mod.rs
+++ b/src/dav/mod.rs
@@ -1,3 +1,5 @@
+mod error;
+mod xml;
mod types;
mod caltypes;
mod acltypes;
@@ -5,6 +7,7 @@ mod versioningtypes;
mod encoder;
mod calencoder;
mod decoder;
+mod realization;
use std::net::SocketAddr;
diff --git a/src/dav/realization.rs b/src/dav/realization.rs
new file mode 100644
index 0000000..22c9cfc
--- /dev/null
+++ b/src/dav/realization.rs
@@ -0,0 +1,41 @@
+use super::types as dav;
+use super::caltypes as cal;
+use super::xml;
+use super::error;
+
+#[derive(Debug, PartialEq)]
+pub struct Disabled(());
+impl xml::QRead<Disabled> for Disabled {
+ async fn qread(&self, xml: &mut xml::Reader<impl xml::IRead>) -> Result<Option<Self>, error::ParsingError> {
+ unreachable!();
+ }
+}
+impl xml::QWrite for Disabled {
+ async fn qwrite(&self, xml: &mut xml::Writer<impl xml::IWrite>) -> Result<(), quick_xml::Error> {
+ unreachable!();
+ }
+}
+
+/// The base WebDAV
+///
+/// Any extension is kooh is disabled through an object we can't build
+/// due to a private inner element.
+pub struct Core {}
+impl dav::Extension for Core {
+ type Error = Disabled;
+ type Property = Disabled;
+ type PropertyRequest = Disabled;
+ type ResourceType = Disabled;
+}
+
+/*
+// WebDAV with the base Calendar implementation (RFC4791)
+pub struct CalendarMin {}
+impl dav::Extension for CalendarMin
+{
+ type Error = cal::Violation;
+ type Property = cal::Property;
+ type PropertyRequest = cal::PropertyRequest;
+ type ResourceType = cal::ResourceType;
+}
+*/
diff --git a/src/dav/types.rs b/src/dav/types.rs
index a1b1c7f..f2eae3a 100644
--- a/src/dav/types.rs
+++ b/src/dav/types.rs
@@ -1,28 +1,20 @@
#![allow(dead_code)]
+use std::fmt::Debug;
use chrono::{DateTime,FixedOffset};
+use super::xml;
+use super::error;
-/// Extension utilities
-pub struct Disabled(());
+/// It's how we implement a DAV extension
+/// (That's the dark magic part...)
+pub trait ExtensionItem<T> = xml::QRead<T> + xml::QWrite + Debug + PartialEq;
pub trait Extension {
- type Error;
- type Property;
- type PropertyRequest;
- type ResourceType;
+ type Error: ExtensionItem<Self::Error>;
+ type Property: ExtensionItem<Self::Property>;
+ type PropertyRequest: ExtensionItem<Self::PropertyRequest>;
+ type ResourceType: ExtensionItem<Self::ResourceType>;
}
-/// No extension
-pub struct NoExtension {
- pub root: bool
-}
-impl Extension for NoExtension {
- type Error = Disabled;
- type Property = Disabled;
- type PropertyRequest = Disabled;
- type ResourceType = Disabled;
-}
-
-
/// 14.1. activelock XML Element
///
/// Name: activelock
@@ -30,6 +22,7 @@ impl Extension for NoExtension {
/// Purpose: Describes a lock on a resource.
/// <!ELEMENT activelock (lockscope, locktype, depth, owner?, timeout?,
/// locktoken?, lockroot)>
+#[derive(Debug, PartialEq)]
pub struct ActiveLock {
pub lockscope: LockScope,
pub locktype: LockType,
@@ -50,6 +43,7 @@ pub struct ActiveLock {
/// elements.
///
/// <!ELEMENT collection EMPTY >
+#[derive(Debug, PartialEq)]
pub struct Collection{}
/// 14.4 depth XML Element
@@ -62,6 +56,7 @@ pub struct Collection{}
/// Value: "0" | "1" | "infinity"
///
/// <!ELEMENT depth (#PCDATA) >
+#[derive(Debug, PartialEq)]
pub enum Depth {
Zero,
One,
@@ -84,8 +79,10 @@ pub enum Depth {
/// postcondition code. Unrecognized elements MUST be ignored.
///
/// <!ELEMENT error ANY >
-pub struct Error<T: Extension>(pub Vec<Violation<T>>);
-pub enum Violation<T: Extension> {
+#[derive(Debug, PartialEq)]
+pub struct Error<E: Extension>(pub Vec<Violation<E>>);
+#[derive(Debug, PartialEq)]
+pub enum Violation<E: Extension> {
/// Name: lock-token-matches-request-uri
///
/// Use with: 409 Conflict
@@ -169,7 +166,7 @@ pub enum Violation<T: Extension> {
CannotModifyProtectedProperty,
/// Specific errors
- Extension(T::Error),
+ Extension(E::Error),
}
/// 14.6. exclusive XML Element
@@ -179,6 +176,7 @@ pub enum Violation<T: Extension> {
/// Purpose: Specifies an exclusive lock.
///
/// <!ELEMENT exclusive EMPTY >
+#[derive(Debug, PartialEq)]
pub struct Exclusive {}
/// 14.7. href XML Element
@@ -194,6 +192,7 @@ pub struct Exclusive {}
/// Value: Simple-ref
///
/// <!ELEMENT href (#PCDATA)>
+#[derive(Debug, PartialEq)]
pub struct Href(pub String);
@@ -209,7 +208,8 @@ pub struct Href(pub String);
/// standards. This element MUST NOT contain text or mixed content.
///
/// <!ELEMENT include ANY >
-pub struct Include<T: Extension>(pub Vec<PropertyRequest<T>>);
+#[derive(Debug, PartialEq)]
+pub struct Include<E: Extension>(pub Vec<PropertyRequest<E>>);
/// 14.9. location XML Element
///
@@ -225,6 +225,7 @@ pub struct Include<T: Extension>(pub Vec<PropertyRequest<T>>);
/// that would be used in a Location header.
///
/// <!ELEMENT location (href)>
+#[derive(Debug, PartialEq)]
pub struct Location(pub Href);
/// 14.10. lockentry XML Element
@@ -235,6 +236,7 @@ pub struct Location(pub Href);
/// resource.
///
/// <!ELEMENT lockentry (lockscope, locktype) >
+#[derive(Debug, PartialEq)]
pub struct LockEntry {
pub lockscope: LockScope,
pub locktype: LockType,
@@ -248,6 +250,7 @@ pub struct LockEntry {
/// specify the type of lock the client wishes to have created.
///
/// <!ELEMENT lockinfo (lockscope, locktype, owner?) >
+#[derive(Debug, PartialEq)]
pub struct LockInfo {
pub lockscope: LockScope,
pub locktype: LockType,
@@ -266,6 +269,7 @@ pub struct LockInfo {
/// values and the response to LOCK requests.
///
/// <!ELEMENT lockroot (href) >
+#[derive(Debug, PartialEq)]
pub struct LockRoot(pub Href);
/// 14.13. lockscope XML Element
@@ -275,6 +279,7 @@ pub struct LockRoot(pub Href);
/// Purpose: Specifies whether a lock is an exclusive lock, or a shared
/// lock.
/// <!ELEMENT lockscope (exclusive | shared) >
+#[derive(Debug, PartialEq)]
pub enum LockScope {
Exclusive,
Shared
@@ -290,6 +295,7 @@ pub enum LockScope {
/// refers to the lock.
///
/// <!ELEMENT locktoken (href) >
+#[derive(Debug, PartialEq)]
pub struct LockToken(pub Href);
/// 14.15. locktype XML Element
@@ -300,6 +306,7 @@ pub struct LockToken(pub Href);
/// specification only defines one lock type, the write lock.
///
/// <!ELEMENT locktype (write) >
+#[derive(Debug, PartialEq)]
pub enum LockType {
/// 14.30. write XML Element
///
@@ -325,8 +332,9 @@ pub enum LockType {
/// response descriptions contained within the responses.
///
/// <!ELEMENT multistatus (response*, responsedescription?) >
-pub struct Multistatus<T: Extension> {
- pub responses: Vec<Response<T>>,
+#[derive(Debug, PartialEq)]
+pub struct Multistatus<E: Extension> {
+ pub responses: Vec<Response<E>>,
pub responsedescription: Option<ResponseDescription>,
}
@@ -354,6 +362,7 @@ pub struct Multistatus<T: Extension> {
///
/// <!ELEMENT owner ANY >
//@FIXME might need support for an extension
+#[derive(Debug, PartialEq)]
pub enum Owner {
Txt(String),
Href(Href),
@@ -373,12 +382,17 @@ pub enum Owner {
/// text or mixed content.
///
/// <!ELEMENT prop ANY >
-pub enum AnyProp<T: Extension> {
- Name(PropName<T>),
- Value(PropValue<T>),
+#[derive(Debug, PartialEq)]
+pub enum AnyProp<E: Extension> {
+ Name(PropName<E>),
+ Value(PropValue<E>),
}
-pub struct PropName<T: Extension>(pub Vec<PropertyRequest<T>>);
-pub struct PropValue<T: Extension>(pub Vec<Property<T>>);
+
+#[derive(Debug, PartialEq)]
+pub struct PropName<E: Extension>(pub Vec<PropertyRequest<E>>);
+
+#[derive(Debug, PartialEq)]
+pub struct PropValue<E: Extension>(pub Vec<Property<E>>);
/// 14.19. propertyupdate XML Element
///
@@ -390,10 +404,13 @@ pub struct PropValue<T: Extension>(pub Vec<Property<T>>);
/// required to modify the properties on the resource.
///
/// <!ELEMENT propertyupdate (remove | set)+ >
-pub struct PropertyUpdate<T: Extension>(pub Vec<PropertyUpdateItem<T>>);
-pub enum PropertyUpdateItem<T: Extension> {
- Remove(Remove<T>),
- Set(Set<T>),
+#[derive(Debug, PartialEq)]
+pub struct PropertyUpdate<E: Extension>(pub Vec<PropertyUpdateItem<E>>);
+
+#[derive(Debug, PartialEq)]
+pub enum PropertyUpdateItem<E: Extension> {
+ Remove(Remove<E>),
+ Set(Set<E>),
}
/// 14.2 allprop XML Element
@@ -430,10 +447,11 @@ pub enum PropertyUpdateItem<T: Extension> {
/// values.
///
/// <!ELEMENT propfind ( propname | (allprop, include?) | prop ) >
-pub enum PropFind<T: Extension> {
+#[derive(Debug, PartialEq)]
+pub enum PropFind<E: Extension> {
PropName,
- AllProp(Option<Include<T>>),
- Prop(PropName<T>),
+ AllProp(Option<Include<E>>),
+ Prop(PropName<E>),
}
/// 14.22 propstat XML Element
@@ -451,10 +469,11 @@ pub enum PropFind<T: Extension> {
/// the properties named in 'prop'.
///
/// <!ELEMENT propstat (prop, status, error?, responsedescription?) >
-pub struct PropStat<T: Extension> {
- pub prop: AnyProp<T>,
+#[derive(Debug, PartialEq)]
+pub struct PropStat<E: Extension> {
+ pub prop: AnyProp<E>,
pub status: Status,
- pub error: Option<Error<T>>,
+ pub error: Option<Error<E>>,
pub responsedescription: Option<ResponseDescription>,
}
@@ -471,7 +490,8 @@ pub struct PropStat<T: Extension> {
/// the names of properties to be removed are required.
///
/// <!ELEMENT remove (prop) >
-pub struct Remove<T: Extension>(pub PropName<T>);
+#[derive(Debug, PartialEq)]
+pub struct Remove<E: Extension>(pub PropName<E>);
/// 14.24. response XML Element
///
@@ -495,14 +515,17 @@ pub struct Remove<T: Extension>(pub PropName<T>);
///
/// <!ELEMENT response (href, ((href*, status)|(propstat+)),
/// error?, responsedescription? , location?) >
-pub enum StatusOrPropstat<T: Extension> {
+#[derive(Debug, PartialEq)]
+pub enum StatusOrPropstat<E: Extension> {
Status(Status),
- PropStat(Vec<PropStat<T>>),
+ PropStat(Vec<PropStat<E>>),
}
-pub struct Response<T: Extension> {
+
+#[derive(Debug, PartialEq)]
+pub struct Response<E: Extension> {
pub href: Href, // It's wrong according to the spec, but I don't understand why there is an href*
- pub status_or_propstat: StatusOrPropstat<T>,
- pub error: Option<Error<T>>,
+ pub status_or_propstat: StatusOrPropstat<E>,
+ pub error: Option<Error<E>>,
pub responsedescription: Option<ResponseDescription>,
pub location: Option<Location>,
}
@@ -518,6 +541,7 @@ pub struct Response<T: Extension> {
/// user.
///
/// <!ELEMENT responsedescription (#PCDATA) >
+#[derive(Debug, PartialEq)]
pub struct ResponseDescription(pub String);
/// 14.26. set XML Element
@@ -536,7 +560,8 @@ pub struct ResponseDescription(pub String);
/// property, and MUST be subsequently retrievable using PROPFIND.
///
/// <!ELEMENT set (prop) >
-pub struct Set<T: Extension>(pub PropValue<T>);
+#[derive(Debug, PartialEq)]
+pub struct Set<E: Extension>(pub PropValue<E>);
/// 14.27. shared XML Element
///
@@ -546,6 +571,7 @@ pub struct Set<T: Extension>(pub PropValue<T>);
///
///
/// <!ELEMENT shared EMPTY >
+#[derive(Debug, PartialEq)]
pub struct Shared {}
@@ -559,6 +585,7 @@ pub struct Shared {}
///
/// <!ELEMENT status (#PCDATA) >
//@FIXME: Better typing is possible with an enum for example
+#[derive(Debug, PartialEq)]
pub struct Status(pub http::status::StatusCode);
/// 14.29. timeout XML Element
@@ -586,6 +613,7 @@ pub struct Status(pub http::status::StatusCode);
/// elapse between granting of the lock at the server, and the automatic
/// removal of the lock. The timeout value for TimeType "Second" MUST
/// NOT be greater than 2^32-1.
+#[derive(Debug, PartialEq)]
pub enum Timeout {
Seconds(u32),
Infinite,
@@ -619,7 +647,8 @@ pub enum Timeout {
/// the header value could include LWS as defined in [RFC2616], Section
/// 4.2. Server implementors SHOULD strip LWS from these values before
/// using as WebDAV property values.
-pub enum PropertyRequest<T: Extension> {
+#[derive(Debug, PartialEq)]
+pub enum PropertyRequest<E: Extension> {
CreationDate,
DisplayName,
GetContentLanguage,
@@ -630,9 +659,11 @@ pub enum PropertyRequest<T: Extension> {
LockDiscovery,
ResourceType,
SupportedLock,
- Extension(T::PropertyRequest),
+ Extension(E::PropertyRequest),
}
-pub enum Property<T: Extension> {
+
+#[derive(Debug, PartialEq)]
+pub enum Property<E: Extension> {
/// 15.1. creationdate Property
///
/// Name: creationdate
@@ -883,7 +914,7 @@ pub enum Property<T: Extension> {
/// <x:collection/>
/// <f:search-results xmlns:f="http://www.example.com/ns"/>
/// </x:resourcetype>
- ResourceType(Vec<ResourceType<T>>),
+ ResourceType(Vec<ResourceType<E>>),
/// 15.10. supportedlock Property
///
@@ -911,10 +942,11 @@ pub enum Property<T: Extension> {
SupportedLock(Vec<LockEntry>),
/// Any extension
- Extension(T::Property),
+ Extension(E::Property),
}
-pub enum ResourceType<T: Extension> {
+#[derive(Debug, PartialEq)]
+pub enum ResourceType<E: Extension> {
Collection,
- Extension(T::ResourceType),
+ Extension(E::ResourceType),
}
diff --git a/src/dav/xml.rs b/src/dav/xml.rs
new file mode 100644
index 0000000..777f99e
--- /dev/null
+++ b/src/dav/xml.rs
@@ -0,0 +1,128 @@
+use std::collections::HashMap;
+use tokio::io::{AsyncWrite, AsyncBufRead};
+use quick_xml::events::{Event, BytesEnd, BytesStart, BytesText};
+use quick_xml::name::{Namespace, QName, PrefixDeclaration, ResolveResult, ResolveResult::*};
+use quick_xml::reader::NsReader;
+
+use super::error::ParsingError;
+
+// Async traits
+pub trait IWrite = AsyncWrite + Unpin;
+pub trait IRead = AsyncBufRead + Unpin + 'static;
+
+// Serialization/Deserialization traits
+pub trait QWrite {
+ async fn qwrite(&self, xml: &mut Writer<impl IWrite>) -> Result<(), quick_xml::Error>;
+}
+pub trait QRead<T> {
+ async fn qread(&self, xml: &mut Reader<impl IRead>) -> Result<Option<T>, ParsingError>;
+}
+
+/// Transform a Rust object into an XML stream of characters
+pub struct Writer<T: IWrite> {
+ pub q: quick_xml::writer::Writer<T>,
+ root: bool,
+}
+impl<T: IWrite> Writer<T> {
+ pub fn create_dav_element(&mut self, name: &str) -> BytesStart<'static> {
+ self.create_ns_element("D", name)
+ }
+ pub fn create_cal_element(&mut self, name: &str) -> BytesStart<'static> {
+ self.create_ns_element("C", name)
+ }
+
+ fn create_ns_element(&mut self, ns: &str, name: &str) -> BytesStart<'static> {
+ let mut start = BytesStart::new(format!("{}:{}", ns, name));
+ //@FIXME not what we want
+ if self.root {
+ start.push_attribute(("xmlns:D", "DAV:"));
+ start.push_attribute(("xmlns:C", "urn:ietf:params:xml:ns:caldav"));
+ self.root = false;
+ }
+ start
+ }
+}
+
+/// Transform an XML stream of characters into a Rust object
+pub struct Reader<T: IRead> {
+ evt: Event<'static>,
+ rdr: NsReader<T>,
+ buf: Vec<u8>,
+}
+impl<T: IRead> Reader<T> {
+ async fn new(mut rdr: NsReader<T>) -> Result<Self, ParsingError> {
+ let mut buf: Vec<u8> = vec![];
+ let evt = rdr.read_event_into_async(&mut buf).await?.into_owned();
+ buf.clear();
+ Ok(Self { evt, rdr, buf })
+ }
+
+ fn peek(&self) -> &Event<'static> {
+ &self.evt
+ }
+
+ /// skip tag. Can't skip end, can't skip eof.
+ async fn skip(&mut self) -> Result<Event<'static>, ParsingError> {
+ match &self.evt {
+ Event::Start(b) => {
+ let _span = self.rdr.read_to_end_into_async(b.to_end().name(), &mut self.buf).await?;
+ self.next().await
+ },
+ Event::End(_) => Err(ParsingError::WrongToken),
+ Event::Eof => Err(ParsingError::Eof),
+ _ => self.next().await,
+ }
+ }
+
+ /// read one more tag
+ async fn next(&mut self) -> Result<Event<'static>, ParsingError> {
+ let evt = self.rdr.read_event_into_async(&mut self.buf).await?.into_owned();
+ self.buf.clear();
+ let old_evt = std::mem::replace(&mut self.evt, evt);
+ Ok(old_evt)
+ }
+
+
+ /// check if this is the desired tag
+ fn is_tag(&self, ns: &[u8], key: &str) -> bool {
+ let qname = match self.peek() {
+ Event::Start(bs) | Event::Empty(bs) => bs.name(),
+ Event::End(be) => be.name(),
+ _ => return false,
+ };
+
+ let (extr_ns, local) = self.rdr.resolve_element(qname);
+
+ if local.into_inner() != key.as_bytes() {
+ return false
+ }
+
+ match extr_ns {
+ ResolveResult::Bound(v) => v.into_inner() == ns,
+ _ => false,
+ }
+ }
+
+ /// find start tag
+ async fn tag_start(&mut self, ns: &[u8], key: &str) -> Result<Event<'static>, ParsingError> {
+ loop {
+ match self.peek() {
+ Event::Start(b) if self.is_tag(ns, key) => break,
+ _ => { self.skip().await?; },
+ }
+ }
+ self.next().await
+ }
+
+ // find stop tag
+ async fn tag_stop(&mut self, ns: &[u8], key: &str) -> Result<Event<'static>, ParsingError> {
+ loop {
+ match self.peek() {
+ Event::End(b) if self.is_tag(ns, key) => break,
+ _ => { self.skip().await?; },
+ }
+ }
+ self.next().await
+ }
+}
+