jsonld-core 0.23.3

JSON-LD core types and traits
Documentation
use crate::{ExpandedDocument, FlattenedDocument, Id, Indexed, IndexedNode, IndexedObject, Node, Object, flattening::NodeMap, object};
use smallvec::SmallVec;
use std::hash::Hash;

/// JSON-LD Quad.
///
/// This is different from an RDF Quad since the object (last element) is a JSON-LD object.
/// A JSON-LD Quad can correspond to multiple RDF Quads.
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>);

/// Property of a quad drawn from a JSON-LD document.
pub enum PropertyRef<'a, T, B> {
    /// The `rdf:type` property, from an `@type` entry.
    Type,
    /// A property given by a node identifier.
    Ref(&'a Id<T, B>),
}

/// Object of a quad drawn from a JSON-LD document.
pub enum ObjectRef<'a, T, B> {
    /// A JSON-LD object.
    Object(&'a Object<T, B>),
    /// A node object.
    Node(&'a Node<T, B>),
    /// An object given by a node identifier.
    Ref(&'a Id<T, B>),
}

/// Documents whose node objects can be read as quads.
pub trait LdQuads<T, B> {
    /// Returns an iterator over the quads of the document.
    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;

/// Iterator over the quads of a document.
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
    }
}