Skip to main content

ld_core/
resource.rs

1use educe::Educe;
2use iri_rs::IriBuf;
3use rdfx::{
4	BlankId, BlankIdBuf, Id, Interpretation, Literal, LocalTerm, Term,
5	interpretation::{ReverseInterpretation, ReverseLocalInterpretation},
6};
7use std::fmt;
8
9use crate::{BorrowedRdfTerm, CowRdfTerm, OwnedRdfTerm};
10
11/// Resource interpretation.
12#[derive(Educe)]
13#[educe(Debug(bound = "I::Resource: fmt::Debug"))]
14pub enum ResourceInterpretation<'a, I: Interpretation> {
15	/// Interpreted resource.
16	Interpreted(&'a I::Resource),
17
18	/// Uninterpreted resource with the given optional lexical representation.
19	///
20	/// It can be used to give an actual interpretation to the resource, bound
21	/// to its lexical representation.
22	Uninterpreted(Option<CowRdfTerm<'a>>),
23}
24
25impl<'a, I: Interpretation> ResourceInterpretation<'a, I> {
26	/// Returns the interpreted resource, if this interpretation is one.
27	pub fn as_interpreted(&self) -> Option<&'a I::Resource> {
28		match self {
29			Self::Interpreted(i) => Some(i),
30			_ => None,
31		}
32	}
33
34	/// Returns the lexical term, if this interpretation is uninterpreted.
35	pub fn as_uninterpreted(&self) -> Option<&CowRdfTerm<'a>> {
36		match self {
37			Self::Uninterpreted(t) => t.as_ref(),
38			_ => None,
39		}
40	}
41
42	/// Resolves this interpretation into a lexical term, looking the resource
43	/// up in `interpretation` when necessary.
44	pub fn into_lexical_representation(self, interpretation: &'a I) -> Option<CowRdfTerm<'a>>
45	where
46		I: ReverseInterpretation + ReverseLocalInterpretation,
47	{
48		match self {
49			Self::Interpreted(r) => {
50				if let Some(i) = interpretation.iris_of(r).next() {
51					return Some(CowRdfTerm::Owned(OwnedRdfTerm::Iri(i.into_owned())));
52				}
53
54				if let Some(l) = interpretation.literals_of(r).next() {
55					return Some(CowRdfTerm::Owned(
56						OwnedRdfTerm::Literal(
57							crate::RdfLiteralRef::Any(&l.value.clone(), l.type_.as_ref())
58								.into_owned(),
59						)
60						.into_self_owned(),
61					));
62				}
63
64				if let Some(b) = interpretation.blank_ids_of(r).next() {
65					return Some(CowRdfTerm::Owned(OwnedRdfTerm::BlankId(b.into_owned())));
66				}
67
68				None
69			}
70			Self::Uninterpreted(t) => t,
71		}
72	}
73}
74
75impl OwnedRdfTerm {
76	fn into_self_owned(self) -> Self {
77		self
78	}
79}
80
81/// Type that can have an interpretation bound to the given lifetime.
82pub trait LinkedDataResourceRef<'a, I: Interpretation = ()> {
83	/// Returns the interpretation of this resource, bound to `'a`.
84	fn interpretation_ref(&self, interpretation: &mut I) -> ResourceInterpretation<'a, I>;
85}
86
87/// Type that can have an interpretation.
88pub trait LinkedDataResource<I: Interpretation = ()> {
89	/// Returns the interpretation of this resource, inserting it into
90	/// `interpretation` if required.
91	fn interpretation(&self, interpretation: &mut I) -> ResourceInterpretation<'_, I>;
92
93	/// Returns the lexical term representing this resource, if any.
94	fn lexical_representation<'a>(&'a self, interpretation: &'a mut I) -> Option<CowRdfTerm<'a>>
95	where
96		I: ReverseInterpretation + ReverseLocalInterpretation,
97	{
98		// Cannot use cleanly because of borrow checker; reconstruct.
99		match self.interpretation(interpretation) {
100			ResourceInterpretation::Interpreted(_) => {
101				// Re-call after reborrowing immutably.
102				self.interpretation(interpretation)
103					.into_lexical_representation(interpretation)
104			}
105			ResourceInterpretation::Uninterpreted(t) => t,
106		}
107	}
108
109	/// Returns the interpretation to use when this resource appears as a
110	/// reference rather than as a subject with properties.
111	fn reference_interpretation(&self, interpretation: &mut I) -> ResourceInterpretation<'_, I> {
112		self.interpretation(interpretation)
113	}
114}
115
116impl<I: Interpretation, T: ?Sized + LinkedDataResource<I>> LinkedDataResource<I> for &T {
117	fn interpretation(&self, interpretation: &mut I) -> ResourceInterpretation<'_, I> {
118		T::interpretation(self, interpretation)
119	}
120}
121
122impl<I: Interpretation, T: ?Sized + LinkedDataResource<I>> LinkedDataResource<I> for Box<T> {
123	fn interpretation(&self, interpretation: &mut I) -> ResourceInterpretation<'_, I> {
124		T::interpretation(self, interpretation)
125	}
126}
127
128impl<I: Interpretation> LinkedDataResource<I> for () {
129	fn interpretation(&self, _interpretation: &mut I) -> ResourceInterpretation<'_, I> {
130		ResourceInterpretation::Uninterpreted(None)
131	}
132}
133
134/// Anonymous lexical representation.
135///
136/// This type implements the `LexicalRepresentation` trait, producing a blank
137/// node identifier.
138pub struct Anonymous;
139
140impl<I: Interpretation> LinkedDataResource<I> for Anonymous {
141	fn interpretation(&self, _interpretation: &mut I) -> ResourceInterpretation<'_, I> {
142		ResourceInterpretation::Uninterpreted(None)
143	}
144}
145
146impl<I: Interpretation> LinkedDataResource<I> for IriBuf {
147	fn interpretation(&self, _interpretation: &mut I) -> ResourceInterpretation<'_, I> {
148		ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Borrowed(BorrowedRdfTerm::Iri(
149			self.as_ref(),
150		))))
151	}
152}
153
154impl<I: Interpretation> LinkedDataResource<I> for iri_rs::Iri<&str> {
155	fn interpretation(&self, _interpretation: &mut I) -> ResourceInterpretation<'_, I> {
156		ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Borrowed(BorrowedRdfTerm::Iri(
157			*self,
158		))))
159	}
160}
161
162impl<I: Interpretation> LinkedDataResource<I> for BlankId {
163	fn interpretation(&self, _interpretation: &mut I) -> ResourceInterpretation<'_, I> {
164		ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Borrowed(BorrowedRdfTerm::BlankId(
165			self,
166		))))
167	}
168}
169
170impl<I: Interpretation> LinkedDataResource<I> for BlankIdBuf {
171	fn interpretation(&self, _interpretation: &mut I) -> ResourceInterpretation<'_, I> {
172		ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Borrowed(BorrowedRdfTerm::BlankId(
173			self.as_ref(),
174		))))
175	}
176}
177
178impl<I: Interpretation> LinkedDataResource<I> for Id {
179	fn interpretation(&self, _interpretation: &mut I) -> ResourceInterpretation<'_, I> {
180		match self {
181			Self::Iri(i) => ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Borrowed(
182				BorrowedRdfTerm::Iri(i.as_ref()),
183			))),
184			Self::BlankId(b) => ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Borrowed(
185				BorrowedRdfTerm::BlankId(b),
186			))),
187		}
188	}
189}
190
191impl<I: Interpretation> LinkedDataResource<I> for Term {
192	fn interpretation(&self, _interpretation: &mut I) -> ResourceInterpretation<'_, I> {
193		match self {
194			Self::Iri(i) => ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Borrowed(
195				BorrowedRdfTerm::Iri(i.as_ref()),
196			))),
197			Self::Literal(l) => ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Borrowed(
198				BorrowedRdfTerm::Literal(crate::RdfLiteralRef::Any(&l.value, l.type_.as_ref())),
199			))),
200		}
201	}
202}
203
204impl<I: Interpretation> LinkedDataResource<I> for LocalTerm {
205	fn interpretation(&self, _interpretation: &mut I) -> ResourceInterpretation<'_, I> {
206		match self {
207			Self::BlankId(b) => ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Borrowed(
208				BorrowedRdfTerm::BlankId(b),
209			))),
210			Self::Named(Term::Iri(i)) => ResourceInterpretation::Uninterpreted(Some(
211				CowRdfTerm::Borrowed(BorrowedRdfTerm::Iri(i.as_ref())),
212			)),
213			Self::Named(Term::Literal(l)) => {
214				ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Borrowed(
215					BorrowedRdfTerm::Literal(crate::RdfLiteralRef::Any(&l.value, l.type_.as_ref())),
216				)))
217			}
218			Self::Triple(_) => ResourceInterpretation::Uninterpreted(None),
219		}
220	}
221}
222
223impl<I: Interpretation> LinkedDataResource<I> for Literal {
224	fn interpretation(&self, _interpretation: &mut I) -> ResourceInterpretation<'_, I> {
225		ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Borrowed(BorrowedRdfTerm::Literal(
226			crate::RdfLiteralRef::Any(self.value.as_str(), self.type_.as_ref()),
227		))))
228	}
229}
230
231impl<I: Interpretation, T: LinkedDataResource<I>> LinkedDataResource<I> for Option<T> {
232	fn interpretation(&self, interpretation: &mut I) -> ResourceInterpretation<'_, I> {
233		match self {
234			Some(t) => t.interpretation(interpretation),
235			None => ResourceInterpretation::Uninterpreted(None),
236		}
237	}
238}