json-ld-core-next 0.21.3

JSON-LD core types and traits
Documentation
use linked_data_next::{
	xsd_types, CowRdfTerm, LinkedData, LinkedDataGraph, LinkedDataPredicateObjects,
	LinkedDataResource, LinkedDataSubject, RdfLiteral, RdfLiteralRef, ResourceInterpretation,
};
use rdf_types::{Interpretation, LiteralTypeRef, Term, Vocabulary};

use crate::{
	object::Literal,
	rdf::{XSD_DOUBLE, XSD_INTEGER},
	Value,
};

impl<V: Vocabulary, I: Interpretation> LinkedDataResource<I, V> for Value<V::Iri> {
	fn interpretation(
		&self,
		vocabulary: &mut V,
		_interpretation: &mut I,
	) -> ResourceInterpretation<I, V> {
		let term = match self {
			Self::Literal(l, ty) => match l {
				Literal::Null => CowRdfTerm::Owned(Term::Literal(RdfLiteral::Xsd(
					xsd_types::Value::String("null".to_string()),
				))),
				Literal::Boolean(b) => CowRdfTerm::Owned(Term::Literal(RdfLiteral::Xsd(
					xsd_types::Value::Boolean((*b).into()),
				))),
				Literal::Number(n) => {
					#[derive(Clone, Copy, Default, PartialEq)]
					enum NumericType {
						Integer,
						Double,
						#[default]
						Unknown,
					}

					impl NumericType {
						pub fn matches(self, other: Self) -> bool {
							self == other || self == Self::Unknown
						}
					}

					let ty = ty
						.as_ref()
						.and_then(|t| vocabulary.iri(t))
						.map(|iri| {
							if iri == XSD_INTEGER {
								NumericType::Integer
							} else if iri == XSD_DOUBLE {
								NumericType::Double
							} else {
								NumericType::Unknown
							}
						})
						.unwrap_or_default();

					let value = match n.as_i64() {
						Some(i) if ty.matches(NumericType::Integer) => {
							xsd_types::Value::Integer(i.into())
						}
						_ => xsd_types::Value::Double(n.as_f64_lossy().into()),
					};

					CowRdfTerm::Owned(Term::Literal(RdfLiteral::Xsd(value)))
				}
				Literal::String(s) => CowRdfTerm::Borrowed(Term::Literal(match ty {
					Some(ty) => RdfLiteralRef::Any(s.as_str(), LiteralTypeRef::Any(ty)),
					None => RdfLiteralRef::Xsd(xsd_types::ValueRef::String(s)),
				})),
			},
			Self::LangString(s) => match s.language().and_then(|l| l.as_well_formed()) {
				Some(tag) => CowRdfTerm::Owned(Term::Literal(RdfLiteral::Any(
					s.as_str().to_owned(),
					rdf_types::LiteralType::LangString(tag.to_owned()),
				))),
				None => CowRdfTerm::Borrowed(Term::Literal(RdfLiteralRef::Xsd(
					xsd_types::ValueRef::String(s.as_str()),
				))),
			},
			Self::Json(json) => CowRdfTerm::Borrowed(Term::Literal(RdfLiteralRef::Json(json))),
		};

		ResourceInterpretation::Uninterpreted(Some(term))
	}
}

impl<T, V: Vocabulary, I: Interpretation> LinkedDataSubject<I, V> for Value<T> {
	fn visit_subject<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
	where
		S: linked_data_next::SubjectVisitor<I, V>,
	{
		visitor.end()
	}
}

impl<T, V: Vocabulary, I: Interpretation> LinkedDataPredicateObjects<I, V> for Value<T> {
	fn visit_objects<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
	where
		S: linked_data_next::PredicateObjectsVisitor<I, V>,
	{
		visitor.end()
	}
}

impl<V: Vocabulary, I: Interpretation> LinkedDataGraph<I, V> for Value<V::Iri> {
	fn visit_graph<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
	where
		S: linked_data_next::GraphVisitor<I, V>,
	{
		visitor.subject(self)?;
		visitor.end()
	}
}

impl<V: Vocabulary, I: Interpretation> LinkedData<I, V> for Value<V::Iri> {
	fn visit<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
	where
		S: linked_data_next::Visitor<I, V>,
	{
		visitor.default_graph(self)?;
		visitor.end()
	}
}