use crate::{ExpandedDocument, FlattenedDocument, Id, Indexed, IndexedNode, IndexedObject, Node, Object, flattening::NodeMap, object};
use smallvec::SmallVec;
use std::hash::Hash;
pub 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>);
pub enum PropertyRef<'a, T, B> {
Type,
Ref(&'a Id<T, B>),
}
pub enum ObjectRef<'a, T, B> {
Object(&'a Object<T, B>),
Node(&'a Node<T, B>),
Ref(&'a Id<T, B>),
}
pub trait LdQuads<T, B> {
fn quads(&self) -> Quads<'_, T, B>;
}
impl<T, B> LdQuads<T, B> for ExpandedDocument<T, B> {
fn quads(&self) -> Quads<'_, T, B> {
let mut stack = SmallVec::new();
stack.push(QuadsFrame::IndexedObjectSet(None, self.iter()));
Quads { stack }
}
}
impl<T, B> LdQuads<T, B> for FlattenedDocument<T, B> {
fn quads(&self) -> Quads<'_, T, B> {
let mut stack = SmallVec::new();
stack.push(QuadsFrame::IndexedNodeSlice(None, self.iter()));
Quads { stack }
}
}
impl<T: Eq + Hash, B: Eq + Hash> LdQuads<T, B> for NodeMap<T, B> {
fn quads(&self) -> Quads<'_, T, B> {
let mut stack = SmallVec::new();
for (id, graph) in self {
stack.push(QuadsFrame::NodeMapGraph(id, graph.nodes()));
}
Quads { stack }
}
}
const STACK_LEN: usize = 6;
pub struct Quads<'a, T, B> {
stack: SmallVec<[QuadsFrame<'a, T, B>; STACK_LEN]>,
}
enum QuadsFrame<'a, T, B> {
NodeMapGraph(Option<&'a Id<T, B>>, crate::flattening::NodeMapGraphNodes<'a, T, B>),
IndexedObjectSet(Option<&'a Id<T, B>>, std::slice::Iter<'a, IndexedObject<T, B>>),
IndexedObjectSlice(Option<&'a Id<T, B>>, std::slice::Iter<'a, IndexedObject<T, B>>),
IndexedNodeSlice(Option<&'a Id<T, B>>, std::slice::Iter<'a, IndexedNode<T, B>>),
NodeTypes(Option<&'a Id<T, B>>, &'a Id<T, B>, std::slice::Iter<'a, Id<T, B>>),
NodeProperties(Option<&'a Id<T, B>>, &'a Id<T, B>, object::node::properties::Iter<'a, T, B>),
NodeReverseProperties(Option<&'a Id<T, B>>, &'a Node<T, B>, object::node::reverse_properties::Iter<'a, T, B>),
NodePropertyObjects(Option<&'a Id<T, B>>, &'a Id<T, B>, &'a Id<T, B>, std::slice::Iter<'a, IndexedObject<T, B>>),
NodeReversePropertySubjects(Option<&'a Id<T, B>>, &'a Node<T, B>, &'a Id<T, B>, std::slice::Iter<'a, IndexedNode<T, B>>),
}
impl<'a, T, B> Quads<'a, T, B> {
fn push_object(&mut self, graph: Option<&'a Id<T, B>>, object: &'a Indexed<Object<T, B>>) {
match object.inner() {
Object::Node(node) => self.push_node(graph, node),
Object::List(objects) => self.stack.push(QuadsFrame::IndexedObjectSlice(graph, objects.iter())),
Object::Value(_) => (),
}
}
fn push_node(&mut self, graph: Option<&'a Id<T, B>>, node: &'a Node<T, B>) {
if let Some(id) = &node.id {
if let Some(graph_entry) = node.graph_entry() {
self.stack.push(QuadsFrame::IndexedObjectSlice(Some(id), graph_entry.iter()));
}
if let Some(included) = node.included_entry() {
self.stack.push(QuadsFrame::IndexedNodeSlice(graph, included.iter()));
}
if let Some(reverse_properties) = node.reverse_properties_entry() {
self.stack.push(QuadsFrame::NodeReverseProperties(graph, node, reverse_properties.iter()));
}
self.stack.push(QuadsFrame::NodeProperties(graph, id, node.properties().iter()));
if let Some(types) = &node.types {
self.stack.push(QuadsFrame::NodeTypes(graph, id, types.iter()));
}
}
}
}
impl<'a, T, B> Iterator for Quads<'a, T, B> {
type Item = QuadRef<'a, T, B>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(last) = self.stack.last_mut() {
match last {
QuadsFrame::NodeMapGraph(graph, nodes) => {
let graph = *graph;
match nodes.next() {
Some(node) => self.push_node(graph, node),
None => {
self.stack.pop();
}
}
}
QuadsFrame::IndexedObjectSet(graph, objects) => {
let graph = *graph;
match objects.next() {
Some(object) => self.push_object(graph, object),
None => {
self.stack.pop();
}
}
}
QuadsFrame::IndexedObjectSlice(graph, objects) => {
let graph = *graph;
match objects.next() {
Some(object) => self.push_object(graph, object),
None => {
self.stack.pop();
}
}
}
QuadsFrame::IndexedNodeSlice(graph, nodes) => {
let graph = *graph;
match nodes.next() {
Some(node) => self.push_node(graph, node),
None => {
self.stack.pop();
}
}
}
QuadsFrame::NodeTypes(graph, subject, types) => {
let (graph, subject) = (*graph, *subject);
match types.next() {
Some(ty) => return Some(QuadRef(graph, subject, PropertyRef::Type, ObjectRef::<T, B>::Ref(ty))),
None => {
self.stack.pop();
}
}
}
QuadsFrame::NodeProperties(graph, subject, properties) => {
let (graph, subject) = (*graph, *subject);
match properties.next() {
Some((property, objects)) => self.stack.push(QuadsFrame::NodePropertyObjects(graph, subject, property, objects.iter())),
None => {
self.stack.pop();
}
}
}
QuadsFrame::NodeReverseProperties(graph, object, reverse_properties) => {
let (graph, object) = (*graph, *object);
match reverse_properties.next() {
Some((property, subjects)) => self
.stack
.push(QuadsFrame::NodeReversePropertySubjects(graph, object, property, subjects.iter())),
None => {
self.stack.pop();
}
}
}
QuadsFrame::NodePropertyObjects(graph, subject, property, objects) => {
let (graph, subject, property) = (*graph, *subject, *property);
match objects.next() {
Some(object) => {
self.push_object(graph, object);
return Some(QuadRef(graph, subject, PropertyRef::Ref(property), ObjectRef::Object(object)));
}
None => {
self.stack.pop();
}
}
}
QuadsFrame::NodeReversePropertySubjects(graph, object, property, subjects) => {
let (graph, object, property) = (*graph, *object, *property);
match subjects.next() {
Some(subject) => {
self.push_node(graph, subject.inner());
if let Some(id) = &subject.id {
return Some(QuadRef(graph, id, PropertyRef::Ref(property), ObjectRef::Node(object)));
}
}
None => {
self.stack.pop();
}
}
}
}
}
None
}
}