From 1dc4940fbe3427326a6e5b70ca4119590ca2e5f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Haudebourg?= Date: Mon, 25 Mar 2024 17:04:15 +0100 Subject: [PATCH] Add `vocabulary::ByRef`. Add `vocabulary::Predicate`. Impl `ExtractFromVocabulary` for `Triple`. Impl `ExtractedFromVocabulary` for `Triple`. --- src/literal/mod.rs | 8 +- src/literal/type.rs | 4 +- src/quad.rs | 36 +++++++-- src/term/id.rs | 19 ++++- src/term/mod.rs | 50 +++++++++--- src/triple.rs | 58 +++++++++++++- src/vocabulary/impl/indexed/literal.rs | 4 +- src/vocabulary/impl/none.rs | 6 +- src/vocabulary/mod.rs | 104 ++++++++++++++++++++++++- 9 files changed, 254 insertions(+), 35 deletions(-) diff --git a/src/literal/mod.rs b/src/literal/mod.rs index 57b6f6c..dec90fc 100644 --- a/src/literal/mod.rs +++ b/src/literal/mod.rs @@ -136,10 +136,10 @@ impl ExtractFromVocabulary for Literal { impl ExtractedFromVocabulary for Literal { type Extracted = Literal; - fn exported_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { + fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { Literal::new( self.value.clone(), - self.type_.exported_from_vocabulary(vocabulary), + self.type_.extracted_from_vocabulary(vocabulary), ) } } @@ -342,10 +342,10 @@ impl<'a, V: IriVocabulary> ExtractFromVocabulary for LiteralRef<'a, V::Iri> { impl<'a, V: IriVocabulary> ExtractedFromVocabulary for LiteralRef<'a, V::Iri> { type Extracted = Literal; - fn exported_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { + fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { Literal::new( self.value.to_owned(), - self.type_.exported_from_vocabulary(vocabulary), + self.type_.extracted_from_vocabulary(vocabulary), ) } } diff --git a/src/literal/type.rs b/src/literal/type.rs index 541880a..1c2d54b 100644 --- a/src/literal/type.rs +++ b/src/literal/type.rs @@ -135,7 +135,7 @@ impl ExtractFromVocabulary for LiteralType { impl ExtractedFromVocabulary for LiteralType { type Extracted = LiteralType; - fn exported_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { + fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { match self { Self::Any(t) => LiteralType::Any(vocabulary.iri(t).unwrap().to_owned()), Self::LangString(t) => LiteralType::LangString(t.clone()), @@ -312,7 +312,7 @@ impl<'a, V: IriVocabulary> ExtractFromVocabulary for LiteralTypeRef<'a, V::Ir impl<'a, V: IriVocabulary> ExtractedFromVocabulary for LiteralTypeRef<'a, V::Iri> { type Extracted = LiteralType; - fn exported_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { + fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { match *self { Self::Any(t) => LiteralType::Any(vocabulary.iri(t).unwrap().to_owned()), Self::LangString(t) => LiteralType::LangString(t.to_owned()), diff --git a/src/quad.rs b/src/quad.rs index b377a20..13494c9 100644 --- a/src/quad.rs +++ b/src/quad.rs @@ -5,7 +5,7 @@ use iref::{Iri, IriBuf}; use crate::{ interpretation::Interpret, vocabulary::{ - EmbedIntoVocabulary, EmbeddedIntoVocabulary, ExtractFromVocabulary, + ByRef, EmbedIntoVocabulary, EmbeddedIntoVocabulary, ExtractFromVocabulary, ExtractedFromVocabulary, TryExtractFromVocabulary, }, GraphLabel, Id, Interpretation, LexicalGraphLabelRef, LexicalObjectRef, LexicalSubjectRef, @@ -320,6 +320,30 @@ impl< } } +impl ExtractFromVocabulary for ByRef> +where + ByRef: ExtractFromVocabulary, + ByRef

: ExtractFromVocabulary, + ByRef: ExtractFromVocabulary, + ByRef: ExtractFromVocabulary, +{ + type Extracted = Quad< + as ExtractFromVocabulary>::Extracted, + as ExtractFromVocabulary>::Extracted, + as ExtractFromVocabulary>::Extracted, + as ExtractFromVocabulary>::Extracted, + >; + + fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted { + Quad( + ByRef(self.0 .0).extract_from_vocabulary(vocabulary), + ByRef(self.0 .1).extract_from_vocabulary(vocabulary), + ByRef(self.0 .2).extract_from_vocabulary(vocabulary), + ByRef(self.0 .3).extract_from_vocabulary(vocabulary), + ) + } +} + impl< V, S: ExtractedFromVocabulary, @@ -330,12 +354,12 @@ impl< { type Extracted = Quad; - fn exported_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { + fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { Quad( - self.0.exported_from_vocabulary(vocabulary), - self.1.exported_from_vocabulary(vocabulary), - self.2.exported_from_vocabulary(vocabulary), - self.3.exported_from_vocabulary(vocabulary), + self.0.extracted_from_vocabulary(vocabulary), + self.1.extracted_from_vocabulary(vocabulary), + self.2.extracted_from_vocabulary(vocabulary), + self.3.extracted_from_vocabulary(vocabulary), ) } } diff --git a/src/term/id.rs b/src/term/id.rs index fef8fbf..c82c7bb 100644 --- a/src/term/id.rs +++ b/src/term/id.rs @@ -6,8 +6,8 @@ use locspan_derive::*; use crate::{ vocabulary::{ - BlankIdVocabulary, EmbedIntoVocabulary, EmbeddedIntoVocabulary, ExtractFromVocabulary, - ExtractedFromVocabulary, IriVocabulary, + BlankIdVocabulary, ByRef, EmbedIntoVocabulary, EmbeddedIntoVocabulary, + ExtractFromVocabulary, ExtractedFromVocabulary, IriVocabulary, }, BlankId, BlankIdBuf, LexicalGraphLabelRef, LexicalSubjectRef, MaybeBlankId, MaybeIri, RdfDisplay, Term, TryAsBlankId, TryAsIri, TryIntoBlankId, TryIntoIri, Vocabulary, @@ -144,7 +144,7 @@ impl, B: EmbeddedIntoVocabulary> EmbeddedInto impl ExtractedFromVocabulary for Id { type Extracted = Id; - fn exported_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { + fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { match self { Self::Iri(i) => Id::Iri(vocabulary.iri(i).unwrap().to_owned()), Self::Blank(b) => Id::Blank(vocabulary.blank_id(b).unwrap().to_owned()), @@ -163,6 +163,19 @@ impl ExtractFromVocabulary for Id ExtractFromVocabulary + for ByRef> +{ + type Extracted = Id; + + fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted { + match self.0 { + Id::Iri(i) => Id::Iri(vocabulary.iri(i).unwrap().to_owned()), + Id::Blank(b) => Id::Blank(vocabulary.blank_id(b).unwrap().to_owned()), + } + } +} + /// Type that can turn an `Id` into an `Id`. pub trait TryExportId { type Error; diff --git a/src/term/mod.rs b/src/term/mod.rs index 8d08273..22e2df5 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -1,7 +1,7 @@ use crate::interpretation::{Interpret, LiteralInterpretationMut}; use crate::vocabulary::{ - EmbedIntoVocabulary, EmbeddedIntoVocabulary, ExtractFromVocabulary, ExtractedFromVocabulary, - LiteralVocabulary, TryExtractFromVocabulary, + ByRef, EmbedIntoVocabulary, EmbeddedIntoVocabulary, ExtractFromVocabulary, + ExtractedFromVocabulary, LiteralVocabulary, TryExtractFromVocabulary, }; use crate::{BlankIdBuf, Literal, RdfDisplay}; use iref::IriBuf; @@ -234,30 +234,56 @@ impl, T: Interpret, impl> ExtractedFromVocabulary for Term -where - V::Literal: ExtractedFromVocabulary, { - type Extracted = Term>::Extracted>; + type Extracted = Term; - fn exported_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { + fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { match self { - Self::Id(i) => Term::Id(i.exported_from_vocabulary(vocabulary)), - Self::Literal(l) => Term::Literal(l.exported_from_vocabulary(vocabulary)), + Self::Id(i) => Term::Id(i.extracted_from_vocabulary(vocabulary)), + Self::Literal(l) => Term::Literal( + vocabulary + .literal(l) + .unwrap() + .extract_from_vocabulary(vocabulary), + ), } } } impl> ExtractFromVocabulary for Term -where - V::Literal: ExtractedFromVocabulary, { - type Extracted = Term>::Extracted>; + type Extracted = Term; fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted { match self { Self::Id(i) => Term::Id(i.extract_from_vocabulary(vocabulary)), - Self::Literal(l) => Term::Literal(l.exported_from_vocabulary(vocabulary)), + Self::Literal(l) => Term::Literal( + vocabulary + .owned_literal(l) + .ok() + .unwrap() + .extract_from_vocabulary(vocabulary), + ), + } + } +} + +impl<'a, V: LiteralVocabulary, I> ExtractFromVocabulary for ByRef> +where + ByRef: ExtractFromVocabulary, +{ + type Extracted = Term< as ExtractFromVocabulary>::Extracted, Literal>; + + fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted { + match self.0 { + Term::Id(i) => Term::Id(ByRef(i).extract_from_vocabulary(vocabulary)), + Term::Literal(l) => Term::Literal( + vocabulary + .literal(l) + .unwrap() + .extract_from_vocabulary(vocabulary), + ), } } } diff --git a/src/triple.rs b/src/triple.rs index db15ca8..fbb6a23 100644 --- a/src/triple.rs +++ b/src/triple.rs @@ -3,7 +3,10 @@ use std::{cmp::Ordering, fmt}; use iref::{Iri, IriBuf}; use crate::{ - vocabulary::{EmbedIntoVocabulary, EmbeddedIntoVocabulary}, + vocabulary::{ + ByRef, EmbedIntoVocabulary, EmbeddedIntoVocabulary, ExtractFromVocabulary, + ExtractedFromVocabulary, + }, Id, LexicalObjectRef, LexicalSubjectRef, Object, Quad, RdfDisplay, Term, }; @@ -200,6 +203,59 @@ impl<'a> LexicalTripleRef<'a> { } } +impl, P: ExtractFromVocabulary, O: ExtractFromVocabulary> + ExtractFromVocabulary for Triple +{ + type Extracted = Triple; + + fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted { + Triple( + self.0.extract_from_vocabulary(vocabulary), + self.1.extract_from_vocabulary(vocabulary), + self.2.extract_from_vocabulary(vocabulary), + ) + } +} + +impl ExtractFromVocabulary for ByRef> +where + ByRef: ExtractFromVocabulary, + ByRef

: ExtractFromVocabulary, + ByRef: ExtractFromVocabulary, +{ + type Extracted = Triple< + as ExtractFromVocabulary>::Extracted, + as ExtractFromVocabulary>::Extracted, + as ExtractFromVocabulary>::Extracted, + >; + + fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted { + Triple( + ByRef(self.0 .0).extract_from_vocabulary(vocabulary), + ByRef(self.0 .1).extract_from_vocabulary(vocabulary), + ByRef(self.0 .2).extract_from_vocabulary(vocabulary), + ) + } +} + +impl< + V, + S: ExtractedFromVocabulary, + P: ExtractedFromVocabulary, + O: ExtractedFromVocabulary, + > ExtractedFromVocabulary for Triple +{ + type Extracted = Triple; + + fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { + Triple( + self.0.extracted_from_vocabulary(vocabulary), + self.1.extracted_from_vocabulary(vocabulary), + self.2.extracted_from_vocabulary(vocabulary), + ) + } +} + impl, P: EmbedIntoVocabulary, O: EmbedIntoVocabulary> EmbedIntoVocabulary for Triple { diff --git a/src/vocabulary/impl/indexed/literal.rs b/src/vocabulary/impl/indexed/literal.rs index 31bf332..1dc93c8 100644 --- a/src/vocabulary/impl/indexed/literal.rs +++ b/src/vocabulary/impl/indexed/literal.rs @@ -49,10 +49,10 @@ where { type Extracted = Literal; - fn exported_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { + fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { let literal = vocabulary.literal(self).unwrap(); let value = literal.value.to_owned(); - let type_ = literal.type_.exported_from_vocabulary(vocabulary); + let type_ = literal.type_.extracted_from_vocabulary(vocabulary); Literal::new(value, type_) } } diff --git a/src/vocabulary/impl/none.rs b/src/vocabulary/impl/none.rs index 76986fa..029d8aa 100644 --- a/src/vocabulary/impl/none.rs +++ b/src/vocabulary/impl/none.rs @@ -1,3 +1,5 @@ +use std::ptr::addr_of_mut; + use crate::{ vocabulary::{ BlankIdVocabulary, BlankIdVocabularyMut, IriVocabulary, IriVocabularyMut, @@ -18,13 +20,13 @@ static mut NO_VOCABULARY: NoVocabulary = (); /// Returns a static reference to unit (no vocabulary). #[inline(always)] pub fn no_vocabulary() -> &'static NoVocabulary { - unsafe { &NO_VOCABULARY } + &() } /// Returns a static mutable reference to unit (no vocabulary). #[inline(always)] pub fn no_vocabulary_mut() -> &'static mut NoVocabulary { - unsafe { &mut NO_VOCABULARY } + unsafe { &mut *addr_of_mut!(NO_VOCABULARY) } } impl IriVocabulary for NoVocabulary { diff --git a/src/vocabulary/mod.rs b/src/vocabulary/mod.rs index 7e4952c..5b79635 100644 --- a/src/vocabulary/mod.rs +++ b/src/vocabulary/mod.rs @@ -12,6 +12,7 @@ mod iri; mod literal; pub use blank_id::*; +use iref::IriBuf; pub use iri::*; pub use literal::*; @@ -90,6 +91,92 @@ impl> EmbeddedIntoVocabulary for Option { } } +/// Wrapper type to allow +/// `Term, &V::Literal>` to be extracted into `Term` +/// using the `ExtractFromVocabulary` trait. +/// +/// There is a limitation in Rust's trait solver forbidding the implementation +/// of `ExtractFromVocabulary` for both +/// `Term, V::Literal>` and +/// `Term, &V::Literal>`. +/// It is detected as a conflicting implementation although an associated type +/// `T::Assoc` can never be equal to its reference `&T::Assoc`. +/// +/// As a workaround, `ExtractFromVocabulary` is implemented for +/// `ExtractFromVocabulary` is implemented for +/// `ByRef, &V::Literal>>` instead. +/// +/// # Example +/// +/// ``` +/// use rdf_types::{Id, Term, vocabulary::{IndexVocabulary, IriVocabularyMut, IriIndex, BlankIdIndex, LiteralIndex, ExtractFromVocabulary, ByRef}}; +/// use static_iref::iri; +/// +/// let mut vocabulary = IndexVocabulary::new(); +/// +/// let iri = vocabulary.insert(iri!("http://example.org/")); +/// let term: Term, &LiteralIndex> = Term::iri(&iri); +/// +/// let _: Term = ByRef(term).extract_from_vocabulary(&vocabulary); +/// ``` +pub struct ByRef(pub T); + +/// Wrapper type to allow an arbitrary type to be recognized as an RDF +/// IRI predicate. +/// +/// # Example +/// +/// ``` +/// use rdf_types::{Id, Term, Quad, LexicalQuad, vocabulary::{IndexVocabulary, IriVocabularyMut, IriIndex, BlankIdIndex, LiteralIndex, ExtractFromVocabulary, Predicate, ByRef}}; +/// use static_iref::iri; +/// +/// let mut vocabulary = IndexVocabulary::new(); +/// +/// type IdRef<'a> = Id<&'a IriIndex, &'a BlankIdIndex>; +/// type TermRef<'a> = Term, &'a LiteralIndex>; +/// type QuadRef<'a> = Quad, &'a IriIndex, TermRef<'a>, IdRef<'a>>; +/// +/// let subject = vocabulary.insert(iri!("http://example.org/#subject")); +/// let predicate = vocabulary.insert(iri!("http://example.org/#property")); +/// let object = vocabulary.insert(iri!("http://example.org/#object")); +/// +/// let quad: QuadRef = Quad( +/// Id::Iri(&subject), +/// &predicate, +/// Term::iri(&object), +/// None +/// ); +/// +/// let _: LexicalQuad = ByRef( +/// quad.map_predicate(Predicate) // ensures the `&IriIndex` type is interpreted as a predicate. +/// ).extract_from_vocabulary(&vocabulary); +/// ``` +pub struct Predicate(pub T); + +impl ExtractedFromVocabulary for Predicate { + type Extracted = IriBuf; + + fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { + vocabulary.iri(&self.0).unwrap().to_owned() + } +} + +impl ExtractFromVocabulary for Predicate { + type Extracted = IriBuf; + + fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted { + vocabulary.owned_iri(self.0).ok().unwrap() + } +} + +impl<'a, V: IriVocabulary> ExtractFromVocabulary for ByRef> { + type Extracted = IriBuf; + + fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted { + vocabulary.iri(self.0 .0).unwrap().to_owned() + } +} + /// Extract the RDF component values (IRIs, blank node identifiers, etc.) /// embedded into the vocabulary `V`. /// @@ -109,6 +196,17 @@ impl, V> ExtractFromVocabulary for Option { } } +impl ExtractFromVocabulary for ByRef> +where + ByRef: ExtractFromVocabulary, +{ + type Extracted = Option< as ExtractFromVocabulary>::Extracted>; + + fn extract_from_vocabulary(self, vocabulary: &V) -> Self::Extracted { + self.0.map(|t| ByRef(t).extract_from_vocabulary(vocabulary)) + } +} + /// Exports the RDF component values (IRIs, blank node identifiers, etc.) /// embedded into the vocabulary `V`. /// @@ -122,15 +220,15 @@ pub trait ExtractedFromVocabulary { /// /// For `V::Iri` the output will be `IriBuf`, for `V::BlankId` it will be /// `BlankIdBuf`, etc. - fn exported_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted; + fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted; } impl, V> ExtractedFromVocabulary for Option { type Extracted = Option; - fn exported_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { + fn extracted_from_vocabulary(&self, vocabulary: &V) -> Self::Extracted { self.as_ref() - .map(|t| t.exported_from_vocabulary(vocabulary)) + .map(|t| t.extracted_from_vocabulary(vocabulary)) } }