use educe::Educe;
use iref::{Iri, IriBuf};
#[cfg(feature = "derive")]
pub use linked_data_derive::{Deserialize, Serialize};
use rdf_types::{
dataset::{PatternMatchingDataset, TraversableDataset},
interpretation::ReverseIriInterpretation,
vocabulary::IriVocabulary,
Interpretation, Vocabulary,
};
#[doc(hidden)]
pub use iref;
#[doc(hidden)]
pub use rdf_types;
#[doc(hidden)]
pub use xsd_types;
#[doc(hidden)]
pub use json_syntax;
mod anonymous;
mod datatypes;
mod graph;
mod r#impl;
mod macros;
mod predicate;
mod quads;
mod rdf;
mod reference;
mod resource;
mod subject;
pub use anonymous::*;
pub use graph::*;
pub use predicate::*;
pub use quads::{
to_interpreted_graph_quads, to_interpreted_quads, to_interpreted_subject_quads,
to_lexical_quads, to_lexical_quads_with, to_lexical_subject_quads,
to_lexical_subject_quads_with, to_quads, to_quads_with, IntoQuadsError,
};
pub use rdf::*;
pub use reference::*;
pub use resource::*;
pub use subject::*;
#[derive(Debug, thiserror::Error)]
pub enum FromLinkedDataError {
#[error("expected IRI")]
ExpectedIri(ContextIris),
#[error("unsupported IRI `{found}`")]
UnsupportedIri {
context: ContextIris,
found: IriBuf,
supported: Option<Vec<IriBuf>>,
},
#[error("expected literal")]
ExpectedLiteral(ContextIris),
#[error("literal type mismatch")]
LiteralTypeMismatch {
context: ContextIris,
expected: Option<IriBuf>,
found: IriBuf,
},
#[error("invalid literal")]
InvalidLiteral(ContextIris),
#[error("missing required value")]
MissingRequiredValue(ContextIris),
#[error("too many values")]
TooManyValues(ContextIris),
#[error("invalid subject")]
InvalidSubject {
context: ContextIris,
subject: Option<IriBuf>,
},
}
impl FromLinkedDataError {
pub fn context(&self) -> &ContextIris {
match self {
Self::ExpectedIri(c) => c,
Self::UnsupportedIri { context, .. } => context,
Self::ExpectedLiteral(c) => c,
Self::LiteralTypeMismatch { context, .. } => context,
Self::InvalidLiteral(c) => c,
Self::MissingRequiredValue(c) => c,
Self::TooManyValues(c) => c,
Self::InvalidSubject { context, .. } => context,
}
}
}
pub trait LinkedData<I: Interpretation = (), V: Vocabulary = ()> {
fn visit<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
where
S: Visitor<I, V>;
}
impl<'a, I: Interpretation, V: Vocabulary, T: ?Sized + LinkedData<I, V>> LinkedData<I, V>
for &'a T
{
fn visit<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
where
S: Visitor<I, V>,
{
T::visit(self, visitor)
}
}
impl<I: Interpretation, V: Vocabulary, T: ?Sized + LinkedData<I, V>> LinkedData<I, V> for Box<T> {
fn visit<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
where
S: Visitor<I, V>,
{
T::visit(self, visitor)
}
}
impl<I: Interpretation, V: Vocabulary> LinkedData<I, V> for Iri {
fn visit<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
where
S: Visitor<I, V>,
{
visitor.end()
}
}
pub trait Visitor<I: Interpretation = (), V: Vocabulary = ()> {
type Ok;
type Error;
fn default_graph<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ?Sized + LinkedDataGraph<I, V>;
fn named_graph<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ?Sized + LinkedDataResource<I, V> + LinkedDataGraph<I, V>;
fn end(self) -> Result<Self::Ok, Self::Error>;
}
impl<'s, I: Interpretation, V: Vocabulary, S: Visitor<I, V>> Visitor<I, V> for &'s mut S {
type Ok = ();
type Error = S::Error;
fn default_graph<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ?Sized + LinkedDataGraph<I, V>,
{
S::default_graph(self, value)
}
fn named_graph<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ?Sized + LinkedDataResource<I, V> + LinkedDataGraph<I, V>,
{
S::named_graph(self, value)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
#[derive(Educe)]
#[educe(Debug(bound = "I::Resource: core::fmt::Debug"), Clone, Copy)]
pub enum ResourceOrIriRef<'a, I: Interpretation> {
Resource(&'a I::Resource),
Iri(&'a Iri),
Anonymous,
}
impl<'a, I: Interpretation> ResourceOrIriRef<'a, I> {
pub fn into_iri<V>(self, vocabulary: &V, interpretation: &I) -> Option<IriBuf>
where
V: IriVocabulary,
I: ReverseIriInterpretation<Iri = V::Iri>,
{
match self {
Self::Resource(r) => interpretation
.iris_of(r)
.next()
.map(|i| vocabulary.iri(i).unwrap().to_owned()),
Self::Iri(i) => Some(i.to_owned()),
Self::Anonymous => None,
}
}
}
#[derive(Educe)]
#[educe(Debug(bound = "I::Resource: core::fmt::Debug"), Clone, Copy)]
pub enum Context<'a, I: Interpretation> {
Subject,
Predicate {
subject: ResourceOrIriRef<'a, I>,
},
Object {
subject: ResourceOrIriRef<'a, I>,
predicate: ResourceOrIriRef<'a, I>,
},
}
impl<'a, I: Interpretation> Context<'a, I> {
pub fn with_subject(self, subject: &'a I::Resource) -> Self {
Self::Predicate {
subject: ResourceOrIriRef::Resource(subject),
}
}
pub fn with_predicate(self, predicate: &'a I::Resource) -> Self {
match self {
Self::Predicate { subject } => Self::Object {
subject,
predicate: ResourceOrIriRef::Resource(predicate),
},
_ => Self::Subject,
}
}
pub fn with_predicate_iri(self, predicate: &'a Iri) -> Self {
match self {
Self::Predicate { subject } => Self::Object {
subject,
predicate: ResourceOrIriRef::Iri(predicate),
},
_ => Self::Subject,
}
}
pub fn with_anonymous_predicate(self) -> Self {
match self {
Self::Predicate { subject } => Self::Object {
subject,
predicate: ResourceOrIriRef::Anonymous,
},
_ => Self::Subject,
}
}
pub fn into_iris<V>(self, vocabulary: &V, interpretation: &I) -> ContextIris
where
V: IriVocabulary,
I: ReverseIriInterpretation<Iri = V::Iri>,
{
match self {
Self::Subject => ContextIris::Subject,
Self::Predicate { subject } => ContextIris::Predicate {
subject: subject.into_iri(vocabulary, interpretation),
},
Self::Object { subject, predicate } => ContextIris::Object {
subject: subject.into_iri(vocabulary, interpretation),
predicate: predicate.into_iri(vocabulary, interpretation),
},
}
}
}
#[derive(Debug, Clone)]
pub enum ContextIris {
Subject,
Predicate {
subject: Option<IriBuf>,
},
Object {
subject: Option<IriBuf>,
predicate: Option<IriBuf>,
},
}
impl<'a, I: Interpretation> Default for Context<'a, I> {
fn default() -> Self {
Self::Subject
}
}
pub trait LinkedDataDeserialize<V: Vocabulary = (), I: Interpretation = ()>: Sized {
fn deserialize_dataset_in(
vocabulary: &V,
interpretation: &I,
dataset: &(impl TraversableDataset<Resource = I::Resource> + PatternMatchingDataset),
context: Context<I>,
) -> Result<Self, FromLinkedDataError>;
fn deserialize_dataset(
vocabulary: &V,
interpretation: &I,
dataset: &(impl TraversableDataset<Resource = I::Resource> + PatternMatchingDataset),
) -> Result<Self, FromLinkedDataError> {
Self::deserialize_dataset_in(vocabulary, interpretation, dataset, Context::default())
}
}