trinja 0.7.1

HTML templating / SSG for RDF(S) resources
Documentation
//! Handle RDF(S) lists

use std::sync::Arc;

use minijinja::{
    Value,
    value::{Enumerator, Object, ObjectRepr},
};
use taganak_core::{
    graphs::{Graph, GraphView},
    terms::Term,
};
use tokio::runtime::Handle;
use tracing::trace;

use crate::ParamsWithEnv;

struct GraphListIter<'e, G> {
    params: ParamsWithEnv<'e, G>,
    current: Option<Arc<Term>>,
}

impl<G> Iterator for GraphListIter<'_, G>
where
    G: Graph + std::fmt::Debug + Sync + 'static,
    Self: 'static,
{
    type Item = Value;

    fn next(&mut self) -> Option<Self::Item> {
        let current = self.current.take()?;
        trace!(?current, "iterator step for");

        let handle = Handle::current();
        let first = handle
            .block_on(async {
                let graph = self.params.graph.read().unwrap();
                graph
                    .view()
                    .await
                    .object(
                        Some(&*current),
                        Some(
                            &"<http://www.w3.org/1999/02/22-rdf-syntax-ns#first>"
                                .try_into()
                                .expect("static IRI"),
                        ),
                    )
                    .await
            })
            .ok()?;
        trace!(?current, ?first, "list element is");

        let rest = handle
            .block_on(async {
                let graph = self.params.graph.read().unwrap();
                graph
                    .view()
                    .await
                    .object(
                        Some(&*current),
                        Some(
                            &"<http://www.w3.org/1999/02/22-rdf-syntax-ns#rest>"
                                .try_into()
                                .expect("static IRI"),
                        ),
                    )
                    .await
            })
            .ok()?;
        trace!(?current, ?rest, "next list item will be");
        self.current = rest;

        first.and_then(|t| super::term_to_value(self.params.clone(), &t))
    }
}

#[derive(Debug, Clone)]
pub(crate) struct GraphList<'e, G> {
    params: ParamsWithEnv<'e, G>,
}

impl<'e, G> GraphList<'e, G>
where
    G: Graph + std::fmt::Debug + Sync + 'static,
{
    pub(crate) fn new(params: ParamsWithEnv<'e, G>) -> Self {
        trace!(?params.graph, ?params.base, "GraphList for");
        Self { params }
    }
}

impl<G> Object for GraphList<'_, G>
where
    G: Graph + std::fmt::Debug + Sync + 'static,
    Self: 'static,
{
    fn repr(self: &Arc<Self>) -> ObjectRepr {
        ObjectRepr::Iterable
    }

    fn enumerate(self: &Arc<Self>) -> Enumerator {
        trace!(?self.params.base, "starting iteration from");
        Enumerator::Iter(Box::new(GraphListIter {
            params: self.params.clone(),
            current: self.params.base.clone(),
        }))
    }
}