webdav_xml/
lib.rs

1// SPDX-FileCopyrightText: d-k-bo <d-k-bo@mailbox.org>
2//
3// SPDX-License-Identifier: MIT OR Apache-2.0
4
5#![allow(rustdoc::redundant_explicit_links)]
6
7//! Definitions and (de)serialization for WebDAV XML elements as defined
8//! in [RFC 4918](http://webdav.org/specs/rfc4918.html#xml.element.definitions).
9//!
10//! Since WebDAV uses XML namespaces and supports custom elements in the
11//! `<DAV:prop />` element, we can't rely on e. g. `serde` to (de)serialize
12//! XML elements.
13//!
14//! Instead, this crate uses the [`Element`](crate::Element) trait to define an
15//! element and [`FromXml`](crate::FromXml)/[`IntoXml`](crate::IntoXml) for
16//! (de)serialization.
17
18mod element;
19pub mod elements;
20mod error;
21pub mod properties;
22mod read;
23mod utils;
24mod value;
25mod write;
26
27use bytes::{BufMut, Bytes};
28
29#[doc(no_inline)]
30pub use nonempty;
31
32pub use self::{
33    element::Element,
34    error::{Error, Result},
35    value::{Value, ValueMap},
36};
37
38/// The default WebDAV namespace
39pub const DAV_NAMESPACE: &str = "DAV:";
40/// The default WebDAV namespace prefix
41pub const DAV_PREFIX: &str = "d";
42
43/// Performs deserialization from XML.
44///
45/// This trait is automatically implemented for any type which implements the
46/// `Element + for<'v> TryFrom<&'v Value, Error = Error>` traits.
47/// As such, `FromXml` shouldn't be implemented directly: [`Element`] and
48/// [`TryFrom<&Value>`] should be implemented instead, and you get the `FromXml`
49/// implementation for free.
50pub trait FromXml: Sized {
51    fn from_xml(xml: impl Into<bytes::Bytes>) -> crate::Result<Self>;
52}
53
54impl FromXml for Value {
55    fn from_xml(xml: impl Into<bytes::Bytes>) -> crate::Result<Self> {
56        crate::read::read_xml(xml)
57    }
58}
59
60impl<E> FromXml for E
61where
62    E: Element + for<'v> TryFrom<&'v Value, Error = Error>,
63{
64    fn from_xml(xml: impl Into<bytes::Bytes>) -> crate::Result<Self> {
65        Value::from_xml(xml)?.to_map()?.get::<E>().required::<E>()?
66    }
67}
68
69/// Performs serialization to XML.
70///
71/// This trait is automatically implemented for any type which implements the
72/// `Element + Into<Value>` traits.
73/// As such, `IntoXml` shouldn't be implemented directly: [`Element`] and
74/// [`Into<Value>`] should be implemented instead, and you get the `IntoXml`
75/// implementation for free.
76pub trait IntoXml: Sized {
77    fn write_xml(self, writer: impl std::io::Write) -> crate::Result<()>;
78    fn into_xml(self) -> crate::Result<Bytes> {
79        let mut xml = bytes::BytesMut::new().writer();
80        self.write_xml(&mut xml)?;
81        Ok(xml.into_inner().freeze())
82    }
83}
84
85impl<T> IntoXml for T
86where
87    T: Element + Into<Value>,
88{
89    fn write_xml(self, writer: impl std::io::Write) -> crate::Result<()> {
90        crate::write::write_xml::<T>(writer, self.into())
91    }
92}
93
94/// A type that can't be instantiated.
95///
96/// Prevents not yet implemented types from being instantiated.
97#[derive(Clone, Debug, PartialEq)]
98enum Todo {}
99
100pub(crate) trait OptionExt<T> {
101    fn required<E: Element>(self) -> crate::Result<T>;
102}
103impl<T> OptionExt<T> for Option<T> {
104    fn required<E: Element>(self) -> crate::Result<T> {
105        self.ok_or(Error::MissingElement(E::LOCAL_NAME))
106    }
107}