Skip to main content

ld_core/
rdf.rs

1use core::fmt;
2use std::borrow::Borrow;
3
4use iri_rs::{Iri, IriBuf, iri};
5use rdfx::{
6	BlankId, BlankIdBuf, Datatype, DatatypeRef, Id, Interpretation, InterpretationMut, Literal,
7	LiteralType, LiteralTypeRef, LocalTerm, LocalTermRef, Quad,
8};
9
10/// Node identifier: an IRI or a blank node identifier.
11pub type RdfId = Id;
12/// Lexical RDF term.
13pub type RdfTerm = LocalTerm;
14/// Borrowed lexical RDF term.
15pub type RdfTermRef<'a> = LocalTermRef<'a>;
16
17/// Lexical RDF quad.
18pub type RdfQuad = Quad<Id, IriBuf, LocalTerm, Id>;
19
20/// RDF quad whose components are resources of the interpretation `I`.
21pub type InterpretedQuad<I> = Quad<
22	<I as Interpretation>::Resource,
23	<I as Interpretation>::Resource,
24	<I as Interpretation>::Resource,
25	<I as Interpretation>::Resource,
26>;
27
28#[derive(Debug, Clone)]
29/// RDF term that is either borrowed or owned.
30pub enum CowRdfTerm<'a> {
31	/// A borrowed term.
32	Borrowed(BorrowedRdfTerm<'a>),
33	/// An owned term.
34	Owned(OwnedRdfTerm),
35}
36
37#[derive(Debug, Clone, Copy)]
38/// Borrowed RDF term.
39pub enum BorrowedRdfTerm<'a> {
40	/// An IRI.
41	Iri(Iri<&'a str>),
42	/// A blank node identifier.
43	BlankId(&'a BlankId),
44	/// A literal.
45	Literal(RdfLiteralRef<'a>),
46}
47
48#[derive(Debug, Clone)]
49/// Owned RDF term.
50pub enum OwnedRdfTerm {
51	/// An IRI.
52	Iri(IriBuf),
53	/// A blank node identifier.
54	BlankId(BlankIdBuf),
55	/// A literal.
56	Literal(RdfLiteral),
57}
58
59impl OwnedRdfTerm {
60	/// Converts this term into a node identifier, unless it is a literal.
61	pub fn into_id(self) -> Option<Id> {
62		match self {
63			Self::Iri(iri) => Some(Id::Iri(iri)),
64			Self::BlankId(b) => Some(Id::BlankId(b)),
65			Self::Literal(_) => None,
66		}
67	}
68}
69
70fn datatype_ref_or_unchecked(ty: Iri<&str>) -> DatatypeRef<'_> {
71	DatatypeRef::new(ty).unwrap_or_else(|_| unsafe { DatatypeRef::new_unchecked(ty) })
72}
73
74fn datatype_or_unchecked(ty: IriBuf) -> Datatype {
75	Datatype::new(ty.clone()).unwrap_or_else(|_| unsafe { Datatype::new_unchecked(ty) })
76}
77
78impl<'a> CowRdfTerm<'a> {
79	/// Creates a borrowed literal term from a lexical value and its datatype.
80	pub fn from_str(value: &'a str, ty: Iri<&'a str>) -> Self {
81		use xsd_rs::ValueRef;
82
83		if ty.as_str() == RDF_JSON.as_str() {
84			use jstrict::Parse;
85			match jstrict::Value::parse_str(value) {
86				Ok((json, _)) => CowRdfTerm::Owned(OwnedRdfTerm::Literal(RdfLiteral::Json(json))),
87				Err(_) => CowRdfTerm::Borrowed(BorrowedRdfTerm::Literal(RdfLiteralRef::Any(
88					value,
89					LiteralTypeRef::Any(datatype_ref_or_unchecked(ty)),
90				))),
91			}
92		} else {
93			match xsd_rs::Datatype::from_iri(&ty) {
94				Some(xsd_rs::Datatype::String(xsd_rs::StringDatatype::String)) => {
95					CowRdfTerm::Borrowed(BorrowedRdfTerm::Literal(RdfLiteralRef::Xsd(
96						ValueRef::String(value),
97					)))
98				}
99				Some(xsd_ty) => match xsd_ty.parse(value) {
100					Ok(xsd_value) => {
101						CowRdfTerm::Owned(OwnedRdfTerm::Literal(RdfLiteral::Xsd(xsd_value)))
102					}
103					Err(_) => CowRdfTerm::Borrowed(BorrowedRdfTerm::Literal(RdfLiteralRef::Any(
104						value,
105						LiteralTypeRef::Any(datatype_ref_or_unchecked(ty)),
106					))),
107				},
108				None => CowRdfTerm::Borrowed(BorrowedRdfTerm::Literal(RdfLiteralRef::Any(
109					value,
110					LiteralTypeRef::Any(datatype_ref_or_unchecked(ty)),
111				))),
112			}
113		}
114	}
115
116	/// Clones this term into an owned one.
117	pub fn into_owned(self) -> OwnedRdfTerm {
118		match self {
119			Self::Borrowed(b) => match b {
120				BorrowedRdfTerm::Iri(i) => OwnedRdfTerm::Iri(i.into()),
121				BorrowedRdfTerm::BlankId(b) => OwnedRdfTerm::BlankId(b.to_owned()),
122				BorrowedRdfTerm::Literal(l) => OwnedRdfTerm::Literal(l.into_owned()),
123			},
124			Self::Owned(o) => o,
125		}
126	}
127}
128
129/// Value that is either borrowed or owned, without requiring [`ToOwned`].
130pub enum CowRef<'a, T> {
131	/// A borrowed value.
132	Borrowed(&'a T),
133	/// An owned value.
134	Owned(T),
135}
136
137impl<'a, T> AsRef<T> for CowRef<'a, T> {
138	fn as_ref(&self) -> &T {
139		match self {
140			Self::Borrowed(t) => t,
141			Self::Owned(t) => t,
142		}
143	}
144}
145
146impl<'a, T> Borrow<T> for CowRef<'a, T> {
147	fn borrow(&self) -> &T {
148		match self {
149			Self::Borrowed(t) => t,
150			Self::Owned(t) => t,
151		}
152	}
153}
154
155/// Value that can be stored as an RDF literal.
156pub trait RdfLiteralValue: From<String> + From<xsd_rs::Value> + From<jstrict::Value> {}
157
158impl<T: From<String> + From<xsd_rs::Value> + From<jstrict::Value>> RdfLiteralValue for T {}
159
160/// Type that can be borrowed as an RDF literal of a given datatype.
161pub trait AsRdfLiteral {
162	/// Borrows this value as an RDF literal of type `ty`.
163	fn as_rdf_literal<'a>(&'a self, ty: LiteralTypeRef<'a>) -> CowRdfLiteral<'a>;
164}
165
166impl AsRdfLiteral for str {
167	fn as_rdf_literal<'a>(&'a self, ty: LiteralTypeRef<'a>) -> CowRdfLiteral<'a> {
168		CowRdfLiteral::Borrowed(RdfLiteralRef::Any(self, ty))
169	}
170}
171
172impl AsRdfLiteral for String {
173	fn as_rdf_literal<'a>(&'a self, ty: LiteralTypeRef<'a>) -> CowRdfLiteral<'a> {
174		self.as_str().as_rdf_literal(ty)
175	}
176}
177
178#[derive(Debug, Clone)]
179/// Owned RDF literal, kept in its most specific known form.
180pub enum RdfLiteral {
181	/// Literal held as a lexical value and a datatype.
182	Any(String, LiteralType),
183	/// Literal held as a parsed XSD value.
184	Xsd(xsd_rs::Value),
185	/// Literal held as a parsed `rdf:JSON` value.
186	Json(jstrict::Value),
187}
188
189impl RdfLiteral {
190	/// Converts this literal into its lexical form.
191	pub fn into_lexical(self) -> Literal {
192		match self {
193			Self::Any(s, ty) => Literal::new(s, ty),
194			Self::Xsd(value) => {
195				let ty = value.datatype().iri().to_owned();
196				Literal::new(value.to_string(), datatype_or_unchecked(ty.into()))
197			}
198			Self::Json(mut value) => {
199				value.canonicalize();
200				Literal::new(value.to_string(), datatype_or_unchecked(RDF_JSON.into()))
201			}
202		}
203	}
204
205	/// Borrows this literal.
206	pub fn as_literal_ref(&self) -> RdfLiteralRef<'_> {
207		match self {
208			Self::Any(value, ty) => RdfLiteralRef::Any(value, ty.as_ref()),
209			Self::Xsd(value) => RdfLiteralRef::Xsd(value.as_ref()),
210			Self::Json(value) => RdfLiteralRef::Json(value),
211		}
212	}
213
214	/// Inserts this literal into `interpretation`, returning its resource.
215	pub fn embed_into<I: InterpretationMut>(self, interpretation: &mut I) -> I::Resource {
216		interpretation.insert_literal(self.into_lexical().into_cow())
217	}
218}
219
220impl fmt::Display for RdfLiteral {
221	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222		match self {
223			Self::Any(v, _) => v.fmt(f),
224			Self::Xsd(v) => v.fmt(f),
225			Self::Json(v) => v.fmt(f),
226		}
227	}
228}
229
230/// The `rdf:JSON` datatype IRI,
231/// <http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON>.
232pub const RDF_JSON: Iri<&'static str> = iri!("http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON");
233
234#[derive(Debug, Clone, Copy)]
235/// Borrowed RDF literal, kept in its most specific known form.
236pub enum RdfLiteralRef<'a> {
237	/// Literal held as a lexical value and a datatype.
238	Any(&'a str, LiteralTypeRef<'a>),
239	/// Literal held as a parsed XSD value.
240	Xsd(xsd_rs::ValueRef<'a>),
241	/// Literal held as a parsed `rdf:JSON` value.
242	Json(&'a jstrict::Value),
243}
244
245impl<'a> RdfLiteralRef<'a> {
246	/// Converts this literal into its lexical form.
247	pub fn into_lexical(self) -> Literal {
248		match self {
249			Self::Any(s, ty) => Literal::new(s.to_owned(), ty.into_owned()),
250			Self::Xsd(value) => {
251				let ty = value.datatype().iri().to_owned();
252				Literal::new(value.to_string(), datatype_or_unchecked(ty.into()))
253			}
254			Self::Json(value) => {
255				let mut value = value.clone();
256				value.canonicalize();
257				Literal::new(value.to_string(), datatype_or_unchecked(RDF_JSON.into()))
258			}
259		}
260	}
261
262	/// Clones this literal into an owned one.
263	pub fn into_owned(self) -> RdfLiteral {
264		match self {
265			Self::Any(value, ty) => RdfLiteral::Any(value.to_owned(), ty.into_owned()),
266			Self::Xsd(value) => RdfLiteral::Xsd(value.into_owned()),
267			Self::Json(value) => RdfLiteral::Json(value.clone()),
268		}
269	}
270}
271
272/// RDF literal that is either borrowed or owned.
273pub enum CowRdfLiteral<'a> {
274	/// A borrowed literal.
275	Borrowed(RdfLiteralRef<'a>),
276	/// An owned literal.
277	Owned(RdfLiteral),
278}
279
280impl<'a> CowRdfLiteral<'a> {
281	/// Clones this literal into an owned one.
282	pub fn into_owned(self) -> RdfLiteral {
283		match self {
284			Self::Borrowed(l) => l.into_owned(),
285			Self::Owned(l) => l,
286		}
287	}
288
289	/// Borrows this literal.
290	pub fn as_literal_ref(&self) -> RdfLiteralRef<'_> {
291		match self {
292			Self::Borrowed(l) => *l,
293			Self::Owned(l) => l.as_literal_ref(),
294		}
295	}
296}