serde_roxmltree/
raw_node.rs

1use std::cell::Cell;
2use std::fmt;
3use std::marker::PhantomData;
4use std::mem::transmute;
5use std::ops::Deref;
6use std::ptr;
7
8use roxmltree::Node;
9use serde_core::de;
10
11use crate::{Deserializer, Source};
12
13/// Captures subtrees from the source
14///
15/// This type must borrow from the source during serialization and therefore requires the use of the [`from_doc`][crate::from_doc] or [`from_node`][crate::from_node] entry points.
16/// It will however recover only the source `document` or `node` lifetime and not the full `input` lifetime.
17///
18/// ```
19/// use roxmltree::Document;
20/// use serde::Deserialize;
21/// use serde_roxmltree::{from_doc, RawNode};
22///
23/// #[derive(Deserialize)]
24/// struct Record<'a> {
25///     #[serde(borrow)]
26///     subtree: RawNode<'a>,
27/// }
28///
29/// let document = Document::parse(r#"<document><subtree><field attribute="bar">foo</field></subtree></document>"#)?;
30///
31/// let record = from_doc::<Record>(&document)?;
32/// assert!(record.subtree.has_tag_name("subtree"));
33/// #
34/// # Ok::<(), Box<dyn std::error::Error>>(())
35/// ```
36#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
37pub struct RawNode<'a>(pub Node<'a, 'a>);
38
39impl<'a> Deref for RawNode<'a> {
40    type Target = Node<'a, 'a>;
41
42    fn deref(&self) -> &Self::Target {
43        &self.0
44    }
45}
46
47impl<'de, 'a> de::Deserialize<'de> for RawNode<'a>
48where
49    'de: 'a,
50{
51    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
52    where
53        D: de::Deserializer<'de>,
54    {
55        struct Visitor<'a>(PhantomData<&'a ()>);
56
57        impl<'de, 'a> de::Visitor<'de> for Visitor<'a>
58        where
59            'de: 'a,
60        {
61            type Value = RawNode<'a>;
62
63            fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
64                fmt.write_str("struct RawNode")
65            }
66
67            fn visit_map<M>(self, _map: M) -> Result<Self::Value, M::Error>
68            where
69                M: de::MapAccess<'de>,
70            {
71                match CURR_NODE.get() {
72                    #[allow(unsafe_code)]
73                    // SAFETY: This is set only while `deserialize_struct` is active.
74                    Some(curr_node) => Ok(RawNode(unsafe {
75                        transmute::<Node<'static, 'static>, Node<'a, 'a>>(curr_node)
76                    })),
77                    None => Err(de::Error::custom("no current node")),
78                }
79            }
80        }
81
82        deserializer.deserialize_struct(RAW_NODE_NAME, &[], Visitor(PhantomData))
83    }
84}
85
86pub fn deserialize_struct<'de, 'input, 'temp, O, F, R>(
87    this: Deserializer<'de, 'input, 'temp, O>,
88    name: &'static str,
89    f: F,
90) -> R
91where
92    F: FnOnce(Deserializer<'de, 'input, 'temp, O>) -> R,
93{
94    let _reset_curr_node = match &this.source {
95        Source::Node(node) if ptr::eq(name, RAW_NODE_NAME) => {
96            let reset_curr_node = ResetCurrNode(CURR_NODE.get());
97
98            #[allow(unsafe_code)]
99            // SAFETY: The guard will reset this before `deserialize_struct` returns.
100            CURR_NODE.set(Some(unsafe {
101                transmute::<Node<'de, 'input>, Node<'static, 'static>>(*node)
102            }));
103
104            Some(reset_curr_node)
105        }
106        _ => None,
107    };
108
109    f(this)
110}
111
112static RAW_NODE_NAME: &str = "RawNode";
113
114thread_local! {
115    static CURR_NODE: Cell<Option<Node<'static, 'static>>> = const { Cell::new(None) };
116}
117
118struct ResetCurrNode(Option<Node<'static, 'static>>);
119
120impl Drop for ResetCurrNode {
121    fn drop(&mut self) {
122        CURR_NODE.set(self.0.take());
123    }
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129
130    use roxmltree::Document;
131    use serde::Deserialize;
132
133    use crate::from_doc;
134
135    #[test]
136    fn raw_node_captures_subtree() {
137        #[derive(Debug, Deserialize)]
138        struct Root<'a> {
139            #[serde(borrow)]
140            foo: RawNode<'a>,
141        }
142
143        let doc = Document::parse(r#"<root><foo><bar qux="42">23</bar>baz</foo></root>"#).unwrap();
144        let val = from_doc::<Root>(&doc).unwrap();
145
146        assert!(val.foo.0.is_element());
147        assert!(val.foo.0.has_tag_name("foo"));
148
149        let children = val.foo.0.children().collect::<Vec<_>>();
150        assert_eq!(children.len(), 2);
151        assert!(children[0].is_element());
152        assert!(children[0].has_tag_name("bar"));
153        assert_eq!(children[0].attribute("qux").unwrap(), "42");
154        assert!(children[1].is_text());
155        assert_eq!(children[1].text().unwrap(), "baz");
156    }
157}