webdav_xml/
value.rs

1// SPDX-FileCopyrightText: d-k-bo <d-k-bo@mailbox.org>
2//
3// SPDX-License-Identifier: MIT OR Apache-2.0
4
5use bytestring::ByteString;
6use indexmap::IndexMap;
7use nonempty::{nonempty, NonEmpty};
8
9use crate::{
10    element::{Element, ElementExt, ElementName},
11    Error,
12};
13
14/// Represents the content of an XML element.
15///
16/// This data structure is intended to be similar to
17/// [`serde_json::Value`](https://docs.rs/serde_json/latest/serde_json/enum.Value.html).
18/// Unlike when deserializing JSON, which has explicit arrays, we have to
19/// manually group multiple adjacent elements into an array-like structure.
20#[derive(Clone, Debug, Default, PartialEq)]
21pub enum Value {
22    /// The element is empty, e.g. `<foo />`
23    #[default]
24    Empty,
25    /// The element contains a text node, e.g. `<foo>bar</foo>`
26    Text(ByteString),
27    /// The element contains other elements, e.g. `<foo><bar /></foo>`
28    Map(ValueMap),
29    /// The parent element contains multiple elements of this type, e.g. `<foo
30    /// /><foo />`
31    List(Box<NonEmpty<Value>>),
32}
33
34impl Value {
35    pub fn to_str(&self) -> Result<&ByteString, Error> {
36        match self {
37            Self::Text(s) => Ok(s),
38            _ => Err(Error::InvalidValueType("expected text")),
39        }
40    }
41    pub fn to_map(&self) -> Result<&ValueMap, Error> {
42        match self {
43            Self::Map(map) => Ok(map),
44            _ => Err(Error::InvalidValueType("expected a map")),
45        }
46    }
47}
48
49impl From<String> for Value {
50    fn from(s: String) -> Self {
51        Value::Text(s.into())
52    }
53}
54
55type InnerValueMap = IndexMap<ElementName<ByteString>, Value>;
56
57/// A mapping from tag names to [`Value`]s.
58#[derive(Clone, Debug, Default, PartialEq)]
59pub struct ValueMap(pub(crate) InnerValueMap);
60
61impl ValueMap {
62    pub fn new() -> Self {
63        Self(IndexMap::new())
64    }
65    /// Extract a child element of a specific type.
66    ///
67    /// # Returns
68    ///
69    /// - `None` if the element doesn't exist
70    /// - `Some(Ok(_))` if the element exists and was successfully extracted
71    /// - `Some(Err(_))` if the element exists and extraction failed
72    pub fn get<'v, E>(&'v self) -> Option<Result<E, Error>>
73    where
74        E: Element + TryFrom<&'v Value, Error = Error>,
75    {
76        self.0
77            .get(&E::element_name::<&'static str>())
78            .map(E::try_from)
79    }
80    /// Extract a non-empty child element of a specific type.
81    ///
82    /// # Returns
83    ///
84    /// - `None` if the element doesn't exist
85    /// - `Some(None)` if the element exists and is empty
86    /// - `Some(Some(Ok(_)))` if the element exists, is not empty and was
87    ///   successfully extracted
88    /// - `Some(Some(Err(_)))` if the element exists, is not empty and
89    ///   extraction failed
90    pub fn get_optional<'v, E>(&'v self) -> Option<Option<Result<E, Error>>>
91    where
92        E: Element + TryFrom<&'v Value, Error = Error>,
93    {
94        self.0
95            .get(&E::element_name::<&'static str>())
96            .map(|value| match value {
97                Value::Empty => None,
98                v => Some(v.try_into()),
99            })
100    }
101    /// Insert a child value into the map.
102    pub fn insert<E: Element>(&mut self, value: Value) {
103        let key = E::element_name();
104        self.insert_raw(key, value)
105    }
106}
107
108impl ValueMap {
109    pub(crate) fn iter_all<'v, E>(&'v self) -> impl Iterator<Item = Result<E, Error>> + 'v
110    where
111        E: Element + TryFrom<&'v Value, Error = Error> + 'v,
112    {
113        enum ElementIter<'a> {
114            List(nonempty::Iter<'a, Value>),
115            Single(std::iter::Once<&'a Value>),
116            Empty,
117        }
118
119        impl<'a> Iterator for ElementIter<'a> {
120            type Item = &'a Value;
121
122            fn next(&mut self) -> Option<Self::Item> {
123                match self {
124                    Self::List(inner) => inner.next(),
125                    Self::Single(value) => value.next(),
126                    Self::Empty => None,
127                }
128            }
129        }
130
131        match self.0.get(&E::element_name::<&'static str>()) {
132            Some(Value::List(list)) => ElementIter::List(list.iter()),
133            Some(value) => ElementIter::Single(std::iter::once(value)),
134            None => ElementIter::Empty,
135        }
136        .map(E::try_from)
137    }
138    // pub(crate) fn iter_all_nonempty<'v, E>(&'v self) -> impl Iterator<Item =
139    // Result<E, Error>> + 'v where
140    //     E: Element + TryFrom<&'v Value, Error = Error>,
141    // {
142    //     self.iter_all()
143    //         .map(|v| v.ok_or(Error::EmptyElement(E::LOCAL_NAME))?)
144    // }
145    // pub(crate) fn get_all_nonempty<'v, E>(&'v self) ->
146    // Result<Option<NonEmpty<E>>, Error> where
147    //     E: Element + TryFrom<&'v Value, Error = Error>,
148    // {
149    //     NonEmpty::try_collect(
150    //         self.iter_all()
151    //             .map(|v| v.ok_or(Error::EmptyElement(E::LOCAL_NAME))?),
152    //     )
153    // }
154    // pub(crate) fn get_all_required<'v, E>(&'v self) -> Result<NonEmpty<E>, Error>
155    // where
156    //     E: Element + TryFrom<&'v Value, Error = Error>,
157    // {
158    //     NonEmpty::try_collect(
159    //         self.iter_all()
160    //             .map(|v| v.ok_or(Error::EmptyElement(E::LOCAL_NAME))?),
161    //     )
162    //     .transpose()
163    //     .ok_or(Error::MissingElement(E::LOCAL_NAME))?
164    // }
165    pub(crate) fn insert_raw(&mut self, key: ElementName<ByteString>, value: Value) {
166        match self.0.get_mut(&key) {
167            Some(old_value) => {
168                *old_value = Value::List(Box::new(nonempty![std::mem::take(old_value), value]));
169            }
170            None => {
171                self.0.insert(key, value);
172            }
173        }
174    }
175}
176
177impl AsRef<InnerValueMap> for ValueMap {
178    fn as_ref(&self) -> &InnerValueMap {
179        &self.0
180    }
181}
182
183impl AsMut<InnerValueMap> for ValueMap {
184    fn as_mut(&mut self) -> &mut InnerValueMap {
185        &mut self.0
186    }
187}
188
189impl From<InnerValueMap> for ValueMap {
190    fn from(map: InnerValueMap) -> Self {
191        Self(map)
192    }
193}