1use crate::{ExpandedDocument, FlattenedDocument, Id, Indexed, IndexedNode, IndexedObject, Node, Object, flattening::NodeMap, object};
2use smallvec::SmallVec;
3use std::hash::Hash;
4
5pub 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
11pub enum PropertyRef<'a, T, B> {
13 Type,
15 Ref(&'a Id<T, B>),
17}
18
19pub enum ObjectRef<'a, T, B> {
21 Object(&'a Object<T, B>),
23 Node(&'a Node<T, B>),
25 Ref(&'a Id<T, B>),
27}
28
29pub trait LdQuads<T, B> {
31 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
65pub 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}