use linked_data::LinkedDataDeserializer;
use rdf_syntax::{CowGroundTerm, CowTerm, Quad, RDF_FIRST, RDF_LIST, RDF_NIL, RDF_REST, RDF_TYPE};
use crate::{
JsonLdIndexed, algorithms::serialization::object::deserialize_object, object::JsonLdList,
};
pub fn try_deserialize_list_object<R, D>(
deserializer: &mut D,
subject: &R,
graph: Option<&R>,
) -> Result<Option<JsonLdList>, D::Error>
where
R: Clone + PartialEq,
D: LinkedDataDeserializer<R>,
{
if !is_list_object(deserializer, subject, graph)? {
return Ok(None);
}
let mut items = Vec::new();
let mut head = subject.clone();
while !deserializer.is_iri(&head, RDF_NIL)? {
let mut first = None;
let mut rest = None;
while let Some(Quad(_, predicate, object, _)) =
deserializer.deserialize_quad(Quad(Some(&head), None, None, Some(graph)))?
{
for p_term in deserializer.terms_of(&predicate)? {
if let CowTerm::Ground(CowGroundTerm::Iri(p_iri)) = p_term? {
if *p_iri == RDF_FIRST {
first = Some(object.clone());
}
if *p_iri == RDF_REST {
rest = Some(object.clone());
}
}
}
}
items.push(JsonLdIndexed::unindexed(deserialize_object(
deserializer,
&first.unwrap(),
graph,
)?));
head = rest.unwrap();
}
Ok(Some(JsonLdList::new(items)))
}
fn is_list_object<R, D>(deserializer: &D, head: &R, graph: Option<&R>) -> Result<bool, D::Error>
where
R: ToOwned + PartialEq,
D: LinkedDataDeserializer<R>,
{
if deserializer.is_iri(head, RDF_NIL)? {
for quad in deserializer.peek_quads(Quad(Some(head), None, None, Some(graph)))? {
let Quad(_, predicate, object, _) = quad?;
if !deserializer.is_iri(predicate, RDF_TYPE)?
|| !deserializer.is_iri(object, RDF_LIST)?
{
return Ok(false);
}
}
return Ok(true);
}
if deserializer
.peek_quads(Quad(None, None, Some(head), Some(graph)))?
.filter(Result::is_ok)
.count()
> 1
{
return Ok(false);
}
let mut first = None;
let mut rest = None;
for quad in deserializer.peek_quads(Quad(Some(head), None, None, Some(graph)))? {
let Quad(_, predicate, object, _) = quad?;
for p_term in deserializer.terms_of(predicate)? {
if let CowTerm::Ground(CowGroundTerm::Iri(p_iri)) = p_term? {
if *p_iri == RDF_TYPE && !deserializer.is_iri(object, RDF_LIST)? {
return Ok(false);
}
if *p_iri == RDF_FIRST
&& let Some(other) = first.replace(object)
&& other != object
{
return Ok(false);
}
if *p_iri == RDF_REST
&& let Some(other) = rest.replace(object)
&& other != object
{
return Ok(false);
}
}
}
}
if first.is_none() {
return Ok(false);
}
let Some(rest) = rest else {
return Ok(false);
};
is_list_object(deserializer, rest, graph)
}