xee_interpreter/xml/
document.rs1use std::sync::atomic;
2
3use ahash::{HashMap, HashMapExt};
4use iri_string::types::{IriStr, IriString};
5use xot::Xot;
6
7use super::Annotations;
8
9static DOCUMENTS_COUNTER: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
10
11fn get_documents_id() -> usize {
12 DOCUMENTS_COUNTER.fetch_add(1, atomic::Ordering::Relaxed)
13}
14
15#[derive(Debug)]
17pub enum DocumentsError {
18 DuplicateUri(String),
20 Parse(xot::ParseError),
22}
23
24impl std::error::Error for DocumentsError {}
25
26impl std::fmt::Display for DocumentsError {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 match self {
29 DocumentsError::DuplicateUri(uri) => write!(f, "Duplicate URI: {}", uri),
30 DocumentsError::Parse(e) => write!(f, "Parse error: {}", e),
31 }
32 }
33}
34
35impl From<xot::ParseError> for DocumentsError {
36 fn from(e: xot::ParseError) -> Self {
37 DocumentsError::Parse(e)
38 }
39}
40
41#[derive(Debug, Clone)]
42pub struct Document {
43 pub(crate) uri: Option<IriString>,
44 root: xot::Node,
45}
46
47impl Document {
48 pub fn root(&self) -> xot::Node {
50 self.root
51 }
52
53 pub(crate) fn cleanup(&self, xot: &mut Xot) {
54 xot.remove(self.root).unwrap();
55 }
56}
57
58#[derive(Debug, Clone)]
69pub struct Documents {
70 id: usize,
71 annotations: Annotations,
72 documents: Vec<Document>,
73 by_uri: HashMap<IriString, DocumentHandle>,
74 uri_by_document_node: HashMap<xot::Node, IriString>,
75}
76
77#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
82pub struct DocumentHandle {
83 pub(crate) documents_id: usize,
84 pub(crate) id: usize,
85}
86
87impl Documents {
88 pub fn new() -> Self {
90 Self {
91 id: get_documents_id(),
92 annotations: Annotations::new(),
93 documents: Vec::new(),
94 by_uri: HashMap::new(),
95 uri_by_document_node: HashMap::new(),
96 }
97 }
98
99 pub fn cleanup(&mut self, xot: &mut Xot) {
101 for document in &self.documents {
102 document.cleanup(xot);
103 }
104 self.annotations.clear();
105 self.documents.clear();
106 self.by_uri.clear();
107 }
108
109 pub fn add_string(
111 &mut self,
112 xot: &mut Xot,
113 uri: Option<&IriStr>,
114 xml: &str,
115 ) -> Result<DocumentHandle, DocumentsError> {
116 let root = xot.parse(xml)?;
117 self.add_root(xot, uri, root)
118 }
119
120 pub fn add_fragment_string(
122 &mut self,
123 xot: &mut Xot,
124 xml: &str,
125 ) -> Result<DocumentHandle, DocumentsError> {
126 let root = xot.parse_fragment(xml)?;
127 self.add_root(xot, None, root)
128 }
129
130 pub fn add_root(
132 &mut self,
133 xot: &Xot,
134 uri: Option<&IriStr>,
135 root: xot::Node,
136 ) -> Result<DocumentHandle, DocumentsError> {
137 if let Some(uri) = uri {
138 if self.by_uri.contains_key(uri) {
139 return Err(DocumentsError::DuplicateUri(uri.as_str().to_string()));
141 }
142 }
143
144 let id = self.documents.len();
145 let handle = DocumentHandle {
146 documents_id: self.id,
147 id,
148 };
149 self.documents.push(Document {
150 uri: uri.map(|uri| uri.to_owned()),
151 root,
152 });
153 if let Some(uri) = uri {
154 self.by_uri.insert(uri.to_owned(), handle);
155 self.uri_by_document_node.insert(root, uri.to_owned());
156 }
157 self.annotations.add(xot, root);
158
159 Ok(handle)
160 }
161
162 pub fn get_by_handle(&self, handle: DocumentHandle) -> Option<&Document> {
164 if handle.documents_id != self.id {
166 return None;
167 }
168 self.documents.get(handle.id)
169 }
170
171 pub fn get_node_by_handle(&self, handle: DocumentHandle) -> Option<xot::Node> {
173 Some(self.get_by_handle(handle)?.root)
174 }
175
176 pub fn get_by_uri(&self, uri: &IriStr) -> Option<&Document> {
180 let handle = self.by_uri.get(uri)?;
181 self.get_by_handle(*handle)
182 }
183
184 pub fn get_node_by_uri(&self, uri: &IriStr) -> Option<xot::Node> {
186 Some(self.get_by_uri(uri)?.root)
187 }
188
189 pub fn get_uri_by_document_node(&self, node: xot::Node) -> Option<IriString> {
193 self.uri_by_document_node.get(&node).cloned()
194 }
195
196 pub fn len(&self) -> usize {
198 self.documents.len()
199 }
200
201 pub fn is_empty(&self) -> bool {
203 self.documents.is_empty()
204 }
205
206 pub(crate) fn annotations(&self) -> &Annotations {
208 &self.annotations
209 }
210}
211
212impl Default for Documents {
213 fn default() -> Self {
214 Self::new()
215 }
216}