json_ld/algorithms/flattening/node_map/
mod.rs1use crate::{
2 ConflictingIndexes, JsonLdBacktraceBuilder, JsonLdExpandedDocument, JsonLdFlattenedDocument,
3 JsonLdIndexed, JsonLdIndexedNode, JsonLdIndexedObject, JsonLdLenient, JsonLdLocated,
4 JsonLdNode, JsonLdObject, JsonLdSourceFile,
5};
6use educe::Educe;
7use json_syntax::tracing::JsonBacktraceBuf;
8use rdf_syntax::{Generator, Id};
9use std::collections::{HashMap, HashSet};
10
11mod builder;
12
13use builder::NodeMapBuilder;
14
15pub type NodeMapExtendError = Box<JsonLdLocated<ConflictingIndexes>>;
16
17pub type Parts = (
18 JsonLdNodeMapGraph,
19 HashMap<JsonLdLenient<Id>, JsonLdNodeMapGraph>,
20);
21
22impl JsonLdExpandedDocument {
23 pub fn generate_node_map_with(
24 &self,
25 generator: impl Generator,
26 location: JsonLdBacktraceBuilder<'_>,
27 ) -> Result<JsonLdNodeMap, NodeMapExtendError> {
28 let mut builder = NodeMapBuilder::new(generator);
29
30 for (i, object) in self.iter().enumerate() {
31 builder.extend_node_map(object, None, location.array_index(i))?;
32 }
33
34 Ok(builder.end())
35 }
36}
37
38#[derive(Educe)]
40#[educe(Default)]
41pub struct JsonLdNodeMap {
42 graphs: HashMap<JsonLdLenient<Id>, JsonLdNodeMapGraph>,
43 default_graph: JsonLdNodeMapGraph,
44}
45
46impl JsonLdNodeMap {
47 pub fn new() -> Self {
48 Self {
49 graphs: HashMap::new(),
50 default_graph: JsonLdNodeMapGraph::new(),
51 }
52 }
53
54 pub fn into_parts(self) -> Parts {
55 (self.default_graph, self.graphs)
56 }
57
58 pub fn iter(&self) -> Iter<'_> {
59 Iter {
60 default_graph: Some(&self.default_graph),
61 graphs: self.graphs.iter(),
62 }
63 }
64
65 pub fn iter_named(
66 &self,
67 ) -> std::collections::hash_map::Iter<'_, JsonLdLenient<Id>, JsonLdNodeMapGraph> {
68 self.graphs.iter()
69 }
70
71 pub fn graph(&self, id: Option<&JsonLdLenient<Id>>) -> Option<&JsonLdNodeMapGraph> {
72 match id {
73 Some(id) => self.graphs.get(id),
74 None => Some(&self.default_graph),
75 }
76 }
77
78 pub fn graph_mut(&mut self, id: Option<&JsonLdLenient<Id>>) -> Option<&mut JsonLdNodeMapGraph> {
79 match id {
80 Some(id) => self.graphs.get_mut(id),
81 None => Some(&mut self.default_graph),
82 }
83 }
84
85 pub fn declare_graph(&mut self, id: JsonLdLenient<Id>) {
86 if let std::collections::hash_map::Entry::Vacant(entry) = self.graphs.entry(id) {
87 entry.insert(JsonLdNodeMapGraph::new());
88 }
89 }
90
91 pub fn merge(self) -> JsonLdNodeMapGraph {
95 let mut result = self.default_graph;
96
97 for (_, graph) in self.graphs {
98 result.merge_with(graph)
99 }
100
101 result
102 }
103
104 pub fn flatten(self, ordered: bool) -> JsonLdFlattenedDocument {
105 let (mut default_graph, named_graphs) = self.into_parts();
106
107 let mut named_graphs: Vec<_> = named_graphs.into_iter().collect();
108 if ordered {
109 named_graphs.sort_by(|a, b| a.0.as_str().cmp(b.0.as_str()));
110 }
111
112 for (graph_id, graph) in named_graphs {
113 let entry = default_graph.declare_node(graph_id, None).ok().unwrap();
114 let mut nodes: Vec<_> = graph.into_nodes().collect();
115 if ordered {
116 nodes.sort_by(|a, b| {
117 a.id.as_ref()
118 .unwrap()
119 .as_str()
120 .cmp(b.id.as_ref().unwrap().as_str())
121 });
122 }
123 entry.set_graph_entry(Some(
124 nodes.into_iter().filter_map(filter_sub_graph).collect(),
125 ));
126 }
127
128 let mut nodes: Vec<_> = default_graph
129 .into_nodes()
130 .filter_map(filter_graph)
131 .collect();
132
133 if ordered {
134 nodes.sort_by(|a, b| {
135 a.id.as_ref()
136 .unwrap()
137 .as_str()
138 .cmp(b.id.as_ref().unwrap().as_str())
139 });
140 }
141
142 nodes
143 }
144
145 pub fn flatten_unordered(self) -> HashSet<JsonLdIndexedNode> {
146 let (mut default_graph, named_graphs) = self.into_parts();
147
148 for (graph_id, graph) in named_graphs {
149 let entry = default_graph.declare_node(graph_id, None).ok().unwrap();
150 entry.set_graph_entry(Some(
151 graph.into_nodes().filter_map(filter_sub_graph).collect(),
152 ));
153 }
154
155 default_graph
156 .into_nodes()
157 .filter_map(filter_graph)
158 .collect()
159 }
160}
161
162pub struct Iter<'a> {
163 default_graph: Option<&'a JsonLdNodeMapGraph>,
164 graphs: std::collections::hash_map::Iter<'a, JsonLdLenient<Id>, JsonLdNodeMapGraph>,
165}
166
167impl<'a> Iterator for Iter<'a> {
168 type Item = (Option<&'a JsonLdLenient<Id>>, &'a JsonLdNodeMapGraph);
169
170 fn next(&mut self) -> Option<Self::Item> {
171 match self.default_graph.take() {
172 Some(default_graph) => Some((None, default_graph)),
173 None => self.graphs.next().map(|(id, graph)| (Some(id), graph)),
174 }
175 }
176}
177
178impl<'a> IntoIterator for &'a JsonLdNodeMap {
179 type Item = (Option<&'a JsonLdLenient<Id>>, &'a JsonLdNodeMapGraph);
180 type IntoIter = Iter<'a>;
181
182 fn into_iter(self) -> Self::IntoIter {
183 self.iter()
184 }
185}
186
187pub struct IntoIter {
188 default_graph: Option<JsonLdNodeMapGraph>,
189 graphs: std::collections::hash_map::IntoIter<JsonLdLenient<Id>, JsonLdNodeMapGraph>,
190}
191
192impl Iterator for IntoIter {
193 type Item = (Option<JsonLdLenient<Id>>, JsonLdNodeMapGraph);
194
195 fn next(&mut self) -> Option<Self::Item> {
196 match self.default_graph.take() {
197 Some(default_graph) => Some((None, default_graph)),
198 None => self.graphs.next().map(|(id, graph)| (Some(id), graph)),
199 }
200 }
201}
202
203impl IntoIterator for JsonLdNodeMap {
204 type Item = (Option<JsonLdLenient<Id>>, JsonLdNodeMapGraph);
205 type IntoIter = IntoIter;
206
207 fn into_iter(self) -> Self::IntoIter {
208 IntoIter {
209 default_graph: Some(self.default_graph),
210 graphs: self.graphs.into_iter(),
211 }
212 }
213}
214
215pub struct JsonLdNodeMapGraphEntry {
218 pub node: JsonLdIndexedNode,
219 pub index_location: Option<JsonBacktraceBuf<JsonLdSourceFile>>,
221}
222
223impl JsonLdNodeMapGraphEntry {
224 fn new(node: JsonLdIndexedNode) -> Self {
225 Self {
226 node,
227 index_location: None,
228 }
229 }
230}
231
232impl std::ops::Deref for JsonLdNodeMapGraphEntry {
233 type Target = JsonLdIndexedNode;
234 fn deref(&self) -> &Self::Target {
235 &self.node
236 }
237}
238
239impl std::ops::DerefMut for JsonLdNodeMapGraphEntry {
240 fn deref_mut(&mut self) -> &mut Self::Target {
241 &mut self.node
242 }
243}
244
245#[derive(Educe)]
246#[educe(Default)]
247pub struct JsonLdNodeMapGraph {
248 nodes: HashMap<JsonLdLenient<Id>, JsonLdNodeMapGraphEntry>,
249}
250
251impl JsonLdNodeMapGraph {
252 pub fn new() -> Self {
253 Self {
254 nodes: HashMap::new(),
255 }
256 }
257}
258
259pub type DeclareNodeResult<'a> = Result<&'a mut JsonLdNodeMapGraphEntry, NodeMapExtendError>;
260
261impl JsonLdNodeMapGraph {
262 pub fn contains(&self, id: &JsonLdLenient<Id>) -> bool {
263 self.nodes.contains_key(id)
264 }
265
266 pub fn get(&self, id: &JsonLdLenient<Id>) -> Option<&JsonLdNodeMapGraphEntry> {
267 self.nodes.get(id)
268 }
269
270 pub fn get_mut(&mut self, id: &JsonLdLenient<Id>) -> Option<&mut JsonLdNodeMapGraphEntry> {
271 self.nodes.get_mut(id)
272 }
273
274 pub fn declare_node(
279 &mut self,
280 id: JsonLdLenient<Id>,
281 index: Option<(&str, JsonBacktraceBuf<JsonLdSourceFile>)>,
282 ) -> DeclareNodeResult<'_> {
283 if let Some(entry) = self.nodes.get_mut(&id) {
284 match (entry.index(), index) {
285 (Some(entry_index), Some((new_index, new_location))) => {
286 if entry_index != new_index {
287 let defined_location = entry.index_location.clone().unwrap_or_default();
288 return Err(Box::new(JsonLdLocated::new(
289 ConflictingIndexes {
290 node_id: id,
291 defined_index: JsonLdLocated::new(
292 entry_index.to_string(),
293 defined_location,
294 ),
295 conflicting_index: new_index.to_string(),
296 },
297 new_location,
298 )));
299 }
300 }
301 (None, Some((new_index, new_location))) => {
302 entry.set_index(Some(new_index.to_owned()));
303 entry.index_location = Some(new_location);
304 }
305 _ => (),
306 }
307 } else {
308 let (index_str, index_location) = match index {
309 Some((s, loc)) => (Some(s.to_owned()), Some(loc)),
310 None => (None, None),
311 };
312 self.nodes.insert(
313 id.clone(),
314 JsonLdNodeMapGraphEntry {
315 node: JsonLdIndexed::new(JsonLdNode::new_with_id(Some(id.clone())), index_str),
316 index_location,
317 },
318 );
319 }
320
321 Ok(self.nodes.get_mut(&id).unwrap())
322 }
323
324 pub fn merge_with(&mut self, other: Self) {
328 for (_, entry) in other {
329 self.merge_node(entry.node)
330 }
331 }
332
333 pub fn merge_node(&mut self, node: JsonLdIndexedNode) {
342 let (node, index) = node.into_parts();
343
344 if let Some(id) = &node.id {
345 if let Some(entry) = self.nodes.get_mut(id) {
346 if let Some(index) = index {
347 entry.set_index(Some(index))
348 }
349 } else {
350 self.nodes.insert(
351 id.clone(),
352 JsonLdNodeMapGraphEntry::new(JsonLdIndexed::new(
353 JsonLdNode::new_with_id(Some(id.clone())),
354 index,
355 )),
356 );
357 }
358
359 let flat_node = self.nodes.get_mut(id).unwrap();
360
361 if let Some(types) = node.types {
362 flat_node.types.get_or_insert_default().extend(types);
363 }
364
365 flat_node.set_graph_entry(node.graph);
366 flat_node.set_included(node.included);
367 flat_node.properties_mut().extend_unique(node.properties);
368
369 if let Some(props) = node.reverse_properties {
370 flat_node
371 .reverse_properties_or_default()
372 .extend_unique(props);
373 }
374 }
375 }
376
377 pub fn nodes(&self) -> NodeMapGraphNodes<'_> {
378 self.nodes.values()
379 }
380
381 pub fn into_nodes(self) -> IntoNodeMapGraphNodes {
382 self.nodes.into_values()
383 }
384}
385
386pub type NodeMapGraphNodes<'a> =
387 std::collections::hash_map::Values<'a, JsonLdLenient<Id>, JsonLdNodeMapGraphEntry>;
388pub type IntoNodeMapGraphNodes =
389 std::collections::hash_map::IntoValues<JsonLdLenient<Id>, JsonLdNodeMapGraphEntry>;
390
391impl IntoIterator for JsonLdNodeMapGraph {
392 type Item = (JsonLdLenient<Id>, JsonLdNodeMapGraphEntry);
393 type IntoIter =
394 std::collections::hash_map::IntoIter<JsonLdLenient<Id>, JsonLdNodeMapGraphEntry>;
395
396 fn into_iter(self) -> Self::IntoIter {
397 self.nodes.into_iter()
398 }
399}
400
401impl<'a> IntoIterator for &'a JsonLdNodeMapGraph {
402 type Item = (&'a JsonLdLenient<Id>, &'a JsonLdNodeMapGraphEntry);
403 type IntoIter =
404 std::collections::hash_map::Iter<'a, JsonLdLenient<Id>, JsonLdNodeMapGraphEntry>;
405
406 fn into_iter(self) -> Self::IntoIter {
407 self.nodes.iter()
408 }
409}
410
411fn filter_graph(entry: JsonLdNodeMapGraphEntry) -> Option<JsonLdIndexedNode> {
412 if entry.index().is_none() && entry.is_empty() {
413 None
414 } else {
415 Some(entry.node)
416 }
417}
418
419fn filter_sub_graph(mut entry: JsonLdNodeMapGraphEntry) -> Option<JsonLdIndexedObject> {
420 if entry.index().is_none() && entry.properties().is_empty() {
421 None
422 } else {
423 entry.set_graph_entry(None);
424 entry.set_included(None);
425 entry.set_reverse_properties(None);
426 Some(entry.node.map_inner(JsonLdObject::node))
427 }
428}