rdom/node/
concrete.rs

1//! Concrete (as opposed to abstract) types of nodes. Each node type is represented in this module.
2
3use crate::internal_prelude::*;
4
5use super::contents::{
6    AttributeNodeStorage, CDataSectionNodeStorage, CommentNodeStorage, DocumentFragmentNodeStorage,
7    DocumentNodeStorage, DocumentTypeNodeStorage, ProcessingInstructionNodeStorage,
8    TextNodeStorage,
9};
10use super::{
11    AnyNodeStorage, Buildable, NodeCommon, NodeContentsArc, NodeContentsWeak, NodeGraphStorage,
12};
13use crate::node_list::NodeList;
14use std::convert::TryFrom;
15crate::use_behaviors!(sandbox_member);
16
17#[derive(Clone)]
18/// A strongly-typed handle to a node with a strong reference.
19/// `S` may be the underlying storage
20/// type of any node.
21pub struct ConcreteNodeArc<S: AnyNodeStorage> {
22    pub(crate) contents: Arc<S>,
23    pub(crate) common: Arc<NodeCommon>,
24}
25
26#[derive(Clone)]
27/// A strongly-typed handle to a node with a weak reference.
28/// `S` may be the underlying storage
29/// type of any node.
30pub struct ConcreteNodeWeak<S: AnyNodeStorage> {
31    pub(crate) contents: Weak<S>,
32    pub(crate) common: Weak<NodeCommon>,
33}
34
35macro_rules! impl_concrete {
36    ($($ti:expr => $name:ident),*) => {
37        paste::paste! {
38            $(
39                impl AnyNodeStorage for [<$name NodeStorage>] {}
40
41                #[doc = "Convenience alias for a strong reference to a(n) " $name " node"]
42                pub type [<$name NodeArc>] = ConcreteNodeArc<[<$name NodeStorage>]>;
43
44                #[doc = "Convenience alias for a weak reference to a(n) " $name " node"]
45                pub type [<$name NodeWeak>] = ConcreteNodeWeak<[<$name NodeStorage>]>;
46
47                impl ConcreteNodeArc<[<$name NodeStorage>]> {
48                    pub(crate) fn new(context: Weak<Sandbox>, contents: Arc<[<$name NodeStorage>]>) ->
49                    ConcreteNodeArc<[<$name NodeStorage>]> {
50                        let common = Arc::new_cyclic(|construction_weak| NodeCommon {
51                            node_graph: NodeGraphStorage::new(AnyNodeWeak {
52                                contents: (&contents).into(),
53                                common: construction_weak.clone(),
54                            }),
55                            context,
56                        });
57
58                        ConcreteNodeArc { contents, common }
59                    }
60                }
61
62                impl Buildable for ConcreteNodeArc<[<$name NodeStorage>]> {
63                    type Storage = [<$name NodeStorage>];
64                }
65
66                impl SandboxMemberBehavior for ConcreteNodeArc<[<$name NodeStorage>]> {
67                    fn get_context(&self) -> Weak<Sandbox> {
68                        self.common.context.clone()
69                    }
70                }
71
72                impl TryFrom<AnyNodeArc> for ConcreteNodeArc<[<$name NodeStorage>]> {
73                    type Error = AnyNodeArc;
74
75                    fn try_from(value: AnyNodeArc) -> Result<Self, Self::Error> {
76                        match value.contents {
77                            NodeContentsArc::$name(element) => {
78                                return Ok(ConcreteNodeArc {
79                                    contents: element,
80                                    common: value.common,
81                                })
82                            },
83                            _ => Err(value),
84                        }
85                    }
86                }
87
88                impl TryFrom<AnyNodeWeak> for ConcreteNodeWeak<[<$name NodeStorage>]> {
89                    type Error = AnyNodeWeak;
90
91                    fn try_from(value: AnyNodeWeak) -> Result<Self, Self::Error> {
92                        match value.contents {
93                            NodeContentsWeak::$name(element) => {
94                                return Ok(ConcreteNodeWeak {
95                                    contents: element,
96                                    common: value.common,
97                                })
98                            },
99                            _ => Err(value),
100                        }
101                    }
102                }
103
104                impl From<ConcreteNodeArc<[<$name NodeStorage>]>> for AnyNodeArc {
105                    fn from(concrete: ConcreteNodeArc<[<$name NodeStorage>]>) -> Self {
106                        AnyNodeArc {
107                            common: concrete.common,
108                            contents: NodeContentsArc::$name(concrete.contents),
109                        }
110                    }
111                }
112
113                impl From<ConcreteNodeWeak<[<$name NodeStorage>]>> for AnyNodeWeak {
114                    fn from(concrete: ConcreteNodeWeak<[<$name NodeStorage>]>) -> Self {
115                        AnyNodeWeak {
116                            common: concrete.common,
117                            contents: NodeContentsWeak::$name(concrete.contents),
118                        }
119                    }
120                }
121
122                impl NodeBehavior for ConcreteNodeArc<[<$name NodeStorage>]> {
123                    fn first_child(&self) -> Option<AnyNodeArc> {
124                        self.common.node_graph.first_child()
125                    }
126
127                    fn last_child(&self) -> Option<AnyNodeArc> {
128                        self.common.node_graph.last_child()
129                    }
130
131                    fn append_child(&self, other: AnyNodeArc) {
132                        self.common.node_graph.append_child(other)
133                    }
134
135                    fn child_nodes(&self) -> Arc<NodeList> {
136                        self.common.node_graph.child_nodes()
137                    }
138
139                    fn clone_node(&self) -> AnyNodeArc {
140                        AnyNodeArc::from(self.clone()).clone_node()
141                    }
142
143                    fn get_node_type(&self) -> isize {
144                        $ti
145                    }
146                }
147            )*
148        }
149    }
150}
151
152impl_concrete! {
153    1 => Element,
154    2 => Attribute,
155    3 => Text,
156    4 => CDataSection,
157    5 => ProcessingInstruction,
158    6 => Comment,
159    7 => Document,
160    8 => DocumentType,
161    9 => DocumentFragment
162}
163
164impl DocumentNodeArc {
165    /// Creates a new text node with the given text contents
166    pub fn create_text_node(&self, text: String) -> TextNodeArc {
167        TextNodeArc::new(self.get_context(), Arc::new(TextNodeStorage { data: text }))
168    }
169}