Skip to main content

jsonld_core/
quad.rs

1use crate::{ExpandedDocument, FlattenedDocument, Id, Indexed, IndexedNode, IndexedObject, Node, Object, flattening::NodeMap, object};
2use smallvec::SmallVec;
3use std::hash::Hash;
4
5/// JSON-LD Quad.
6///
7/// This is different from an RDF Quad since the object (last element) is a JSON-LD object.
8/// A JSON-LD Quad can correspond to multiple RDF Quads.
9pub struct QuadRef<'a, T, B>(pub Option<&'a Id<T, B>>, pub &'a Id<T, B>, pub PropertyRef<'a, T, B>, pub ObjectRef<'a, T, B>);
10
11/// Property of a quad drawn from a JSON-LD document.
12pub enum PropertyRef<'a, T, B> {
13    /// The `rdf:type` property, from an `@type` entry.
14    Type,
15    /// A property given by a node identifier.
16    Ref(&'a Id<T, B>),
17}
18
19/// Object of a quad drawn from a JSON-LD document.
20pub enum ObjectRef<'a, T, B> {
21    /// A JSON-LD object.
22    Object(&'a Object<T, B>),
23    /// A node object.
24    Node(&'a Node<T, B>),
25    /// An object given by a node identifier.
26    Ref(&'a Id<T, B>),
27}
28
29/// Documents whose node objects can be read as quads.
30pub trait LdQuads<T, B> {
31    /// Returns an iterator over the quads of the document.
32    fn quads(&self) -> Quads<'_, T, B>;
33}
34
35impl<T, B> LdQuads<T, B> for ExpandedDocument<T, B> {
36    fn quads(&self) -> Quads<'_, T, B> {
37        let mut stack = SmallVec::new();
38        stack.push(QuadsFrame::IndexedObjectSet(None, self.iter()));
39        Quads { stack }
40    }
41}
42
43impl<T, B> LdQuads<T, B> for FlattenedDocument<T, B> {
44    fn quads(&self) -> Quads<'_, T, B> {
45        let mut stack = SmallVec::new();
46        stack.push(QuadsFrame::IndexedNodeSlice(None, self.iter()));
47        Quads { stack }
48    }
49}
50
51impl<T: Eq + Hash, B: Eq + Hash> LdQuads<T, B> for NodeMap<T, B> {
52    fn quads(&self) -> Quads<'_, T, B> {
53        let mut stack = SmallVec::new();
54
55        for (id, graph) in self {
56            stack.push(QuadsFrame::NodeMapGraph(id, graph.nodes()));
57        }
58
59        Quads { stack }
60    }
61}
62
63const STACK_LEN: usize = 6;
64
65/// Iterator over the quads of a document.
66pub struct Quads<'a, T, B> {
67    stack: SmallVec<[QuadsFrame<'a, T, B>; STACK_LEN]>,
68}
69
70enum QuadsFrame<'a, T, B> {
71    NodeMapGraph(Option<&'a Id<T, B>>, crate::flattening::NodeMapGraphNodes<'a, T, B>),
72    IndexedObjectSet(Option<&'a Id<T, B>>, std::slice::Iter<'a, IndexedObject<T, B>>),
73    IndexedObjectSlice(Option<&'a Id<T, B>>, std::slice::Iter<'a, IndexedObject<T, B>>),
74    IndexedNodeSlice(Option<&'a Id<T, B>>, std::slice::Iter<'a, IndexedNode<T, B>>),
75    NodeTypes(Option<&'a Id<T, B>>, &'a Id<T, B>, std::slice::Iter<'a, Id<T, B>>),
76    NodeProperties(Option<&'a Id<T, B>>, &'a Id<T, B>, object::node::properties::Iter<'a, T, B>),
77    NodeReverseProperties(Option<&'a Id<T, B>>, &'a Node<T, B>, object::node::reverse_properties::Iter<'a, T, B>),
78    NodePropertyObjects(Option<&'a Id<T, B>>, &'a Id<T, B>, &'a Id<T, B>, std::slice::Iter<'a, IndexedObject<T, B>>),
79    NodeReversePropertySubjects(Option<&'a Id<T, B>>, &'a Node<T, B>, &'a Id<T, B>, std::slice::Iter<'a, IndexedNode<T, B>>),
80}
81
82impl<'a, T, B> Quads<'a, T, B> {
83    fn push_object(&mut self, graph: Option<&'a Id<T, B>>, object: &'a Indexed<Object<T, B>>) {
84        match object.inner() {
85            Object::Node(node) => self.push_node(graph, node),
86            Object::List(objects) => self.stack.push(QuadsFrame::IndexedObjectSlice(graph, objects.iter())),
87            Object::Value(_) => (),
88        }
89    }
90
91    fn push_node(&mut self, graph: Option<&'a Id<T, B>>, node: &'a Node<T, B>) {
92        if let Some(id) = &node.id {
93            if let Some(graph_entry) = node.graph_entry() {
94                self.stack.push(QuadsFrame::IndexedObjectSlice(Some(id), graph_entry.iter()));
95            }
96
97            if let Some(included) = node.included_entry() {
98                self.stack.push(QuadsFrame::IndexedNodeSlice(graph, included.iter()));
99            }
100
101            if let Some(reverse_properties) = node.reverse_properties_entry() {
102                self.stack.push(QuadsFrame::NodeReverseProperties(graph, node, reverse_properties.iter()));
103            }
104
105            self.stack.push(QuadsFrame::NodeProperties(graph, id, node.properties().iter()));
106
107            if let Some(types) = &node.types {
108                self.stack.push(QuadsFrame::NodeTypes(graph, id, types.iter()));
109            }
110        }
111    }
112}
113
114impl<'a, T, B> Iterator for Quads<'a, T, B> {
115    type Item = QuadRef<'a, T, B>;
116
117    fn next(&mut self) -> Option<Self::Item> {
118        while let Some(last) = self.stack.last_mut() {
119            match last {
120                QuadsFrame::NodeMapGraph(graph, nodes) => {
121                    let graph = *graph;
122                    match nodes.next() {
123                        Some(node) => self.push_node(graph, node),
124                        None => {
125                            self.stack.pop();
126                        }
127                    }
128                }
129                QuadsFrame::IndexedObjectSet(graph, objects) => {
130                    let graph = *graph;
131                    match objects.next() {
132                        Some(object) => self.push_object(graph, object),
133                        None => {
134                            self.stack.pop();
135                        }
136                    }
137                }
138                QuadsFrame::IndexedObjectSlice(graph, objects) => {
139                    let graph = *graph;
140                    match objects.next() {
141                        Some(object) => self.push_object(graph, object),
142                        None => {
143                            self.stack.pop();
144                        }
145                    }
146                }
147                QuadsFrame::IndexedNodeSlice(graph, nodes) => {
148                    let graph = *graph;
149                    match nodes.next() {
150                        Some(node) => self.push_node(graph, node),
151                        None => {
152                            self.stack.pop();
153                        }
154                    }
155                }
156                QuadsFrame::NodeTypes(graph, subject, types) => {
157                    let (graph, subject) = (*graph, *subject);
158                    match types.next() {
159                        Some(ty) => return Some(QuadRef(graph, subject, PropertyRef::Type, ObjectRef::<T, B>::Ref(ty))),
160                        None => {
161                            self.stack.pop();
162                        }
163                    }
164                }
165                QuadsFrame::NodeProperties(graph, subject, properties) => {
166                    let (graph, subject) = (*graph, *subject);
167                    match properties.next() {
168                        Some((property, objects)) => self.stack.push(QuadsFrame::NodePropertyObjects(graph, subject, property, objects.iter())),
169                        None => {
170                            self.stack.pop();
171                        }
172                    }
173                }
174                QuadsFrame::NodeReverseProperties(graph, object, reverse_properties) => {
175                    let (graph, object) = (*graph, *object);
176                    match reverse_properties.next() {
177                        Some((property, subjects)) => self
178                            .stack
179                            .push(QuadsFrame::NodeReversePropertySubjects(graph, object, property, subjects.iter())),
180                        None => {
181                            self.stack.pop();
182                        }
183                    }
184                }
185                QuadsFrame::NodePropertyObjects(graph, subject, property, objects) => {
186                    let (graph, subject, property) = (*graph, *subject, *property);
187                    match objects.next() {
188                        Some(object) => {
189                            self.push_object(graph, object);
190                            return Some(QuadRef(graph, subject, PropertyRef::Ref(property), ObjectRef::Object(object)));
191                        }
192                        None => {
193                            self.stack.pop();
194                        }
195                    }
196                }
197                QuadsFrame::NodeReversePropertySubjects(graph, object, property, subjects) => {
198                    let (graph, object, property) = (*graph, *object, *property);
199                    match subjects.next() {
200                        Some(subject) => {
201                            self.push_node(graph, subject.inner());
202                            if let Some(id) = &subject.id {
203                                return Some(QuadRef(graph, id, PropertyRef::Ref(property), ObjectRef::Node(object)));
204                            }
205                        }
206                        None => {
207                            self.stack.pop();
208                        }
209                    }
210                }
211            }
212        }
213
214        None
215    }
216}