linked_data_next/
rdf.rs

1use core::fmt;
2use std::borrow::Borrow;
3
4use educe::Educe;
5use iref::Iri;
6use rdf_types::{
7	vocabulary::{
8		BlankIdVocabulary, EmbedIntoVocabulary, IriVocabulary, IriVocabularyMut, LiteralVocabulary,
9		LiteralVocabularyMut,
10	},
11	Id, Interpretation, LiteralType, LiteralTypeRef, Quad, Term, Vocabulary,
12};
13
14pub type RdfId<V> = Id<<V as IriVocabulary>::Iri, <V as BlankIdVocabulary>::BlankId>;
15pub type RdfTerm<V> = Term<RdfId<V>, RdfLiteral<V>>;
16
17pub type RdfIdRef<'a, V> = Id<&'a <V as IriVocabulary>::Iri, &'a <V as BlankIdVocabulary>::BlankId>;
18pub type RdfTermRef<'a, V> = Term<RdfIdRef<'a, V>, RdfLiteralRef<'a, V>>;
19
20pub type RdfQuad<V = ()> = Quad<
21	RdfId<V>,
22	<V as IriVocabulary>::Iri,
23	Term<RdfId<V>, <V as LiteralVocabulary>::Literal>,
24	RdfId<V>,
25>;
26
27pub type InterpretedQuad<I> = Quad<<I as Interpretation>::Resource>;
28
29#[derive(Educe)]
30#[educe(Debug(bound = "V::Iri: fmt::Debug, V::BlankId: fmt::Debug"))]
31pub enum CowRdfTerm<'a, V: Vocabulary> {
32	Borrowed(RdfTermRef<'a, V>),
33	Owned(RdfTerm<V>),
34}
35
36impl<'a, V: Vocabulary> CowRdfTerm<'a, V> {
37	pub fn from_str(vocabulary: &V, value: &'a str, ty: &'a V::Iri) -> Self {
38		use xsd_types::ValueRef;
39
40		let ty_iri = vocabulary.iri(ty).unwrap();
41
42		if ty_iri == RDF_JSON {
43			use json_syntax::Parse;
44			match json_syntax::Value::parse_str(value) {
45				Ok((json, _)) => CowRdfTerm::Owned(RdfTerm::Literal(RdfLiteral::Json(json))),
46				Err(_) => CowRdfTerm::Borrowed(RdfTermRef::Literal(RdfLiteralRef::Any(
47					value,
48					LiteralTypeRef::Any(ty),
49				))),
50			}
51		} else {
52			match xsd_types::Datatype::from_iri(ty_iri) {
53				Some(xsd_types::Datatype::String(xsd_types::StringDatatype::String)) => {
54					CowRdfTerm::Borrowed(RdfTermRef::Literal(RdfLiteralRef::Xsd(ValueRef::String(
55						value,
56					))))
57				}
58				Some(xsd_ty) => match xsd_ty.parse(value) {
59					Ok(xsd_value) => {
60						CowRdfTerm::Owned(RdfTerm::Literal(RdfLiteral::Xsd(xsd_value)))
61					}
62					Err(_) => CowRdfTerm::Borrowed(RdfTermRef::Literal(RdfLiteralRef::Any(
63						value,
64						LiteralTypeRef::Any(ty),
65					))),
66				},
67				None => CowRdfTerm::Borrowed(RdfTermRef::Literal(RdfLiteralRef::Any(
68					value,
69					LiteralTypeRef::Any(ty),
70				))),
71			}
72		}
73	}
74}
75
76pub enum CowRef<'a, T> {
77	Borrowed(&'a T),
78	Owned(T),
79}
80
81impl<T> AsRef<T> for CowRef<'_, T> {
82	fn as_ref(&self) -> &T {
83		match self {
84			Self::Borrowed(t) => t,
85			Self::Owned(t) => t,
86		}
87	}
88}
89
90impl<T> Borrow<T> for CowRef<'_, T> {
91	fn borrow(&self) -> &T {
92		match self {
93			Self::Borrowed(t) => t,
94			Self::Owned(t) => t,
95		}
96	}
97}
98
99impl<'a, V: Vocabulary> CowRdfTerm<'a, V> {
100	#[allow(clippy::type_complexity)]
101	pub fn into_term(
102		self,
103	) -> Term<Id<CowRef<'a, V::Iri>, CowRef<'a, V::BlankId>>, CowRdfLiteral<'a, V>> {
104		match self {
105			Self::Borrowed(Term::Id(Id::Iri(i))) => Term::Id(Id::Iri(CowRef::Borrowed(i))),
106			Self::Borrowed(Term::Id(Id::Blank(b))) => Term::Id(Id::Blank(CowRef::Borrowed(b))),
107			Self::Borrowed(Term::Literal(l)) => Term::Literal(CowRdfLiteral::Borrowed(l)),
108			Self::Owned(Term::Id(Id::Iri(i))) => Term::Id(Id::Iri(CowRef::Owned(i))),
109			Self::Owned(Term::Id(Id::Blank(b))) => Term::Id(Id::Blank(CowRef::Owned(b))),
110			Self::Owned(Term::Literal(l)) => Term::Literal(CowRdfLiteral::Owned(l)),
111		}
112	}
113
114	pub fn as_term_ref(&self) -> RdfTermRef<V> {
115		match self {
116			Self::Borrowed(t) => *t,
117			Self::Owned(t) => match t {
118				Term::Id(Id::Iri(i)) => Term::Id(Id::Iri(i)),
119				Term::Id(Id::Blank(b)) => Term::Id(Id::Blank(b)),
120				Term::Literal(l) => Term::Literal(l.as_literal_ref()),
121			},
122		}
123	}
124
125	pub fn into_owned(self) -> RdfTerm<V>
126	where
127		V::Iri: Clone,
128		V::BlankId: Clone,
129	{
130		match self {
131			Self::Borrowed(t) => match t {
132				Term::Id(Id::Iri(i)) => Term::Id(Id::Iri(i.clone())),
133				Term::Id(Id::Blank(b)) => Term::Id(Id::Blank(b.clone())),
134				Term::Literal(l) => Term::Literal(l.into_owned()),
135			},
136			Self::Owned(t) => t,
137		}
138	}
139}
140
141pub trait RdfLiteralValue:
142	From<String> + From<xsd_types::Value> + From<json_syntax::Value>
143{
144}
145
146impl<T: From<String> + From<xsd_types::Value> + From<json_syntax::Value>> RdfLiteralValue for T {}
147
148pub trait AsRdfLiteral<V: IriVocabulary + LiteralVocabulary> {
149	fn as_rdf_literal<'a>(
150		&'a self,
151		vocabulary: &V,
152		ty: LiteralTypeRef<'a, V::Iri>,
153	) -> CowRdfLiteral<'a, V>;
154}
155
156impl<V: IriVocabulary + LiteralVocabulary> AsRdfLiteral<V> for str {
157	fn as_rdf_literal<'a>(
158		&'a self,
159		_vocabulary: &V,
160		ty: LiteralTypeRef<'a, V::Iri>,
161	) -> CowRdfLiteral<'a, V> {
162		CowRdfLiteral::Borrowed(RdfLiteralRef::Any(self, ty))
163	}
164}
165
166impl<V: IriVocabulary + LiteralVocabulary> AsRdfLiteral<V> for String {
167	fn as_rdf_literal<'a>(
168		&'a self,
169		vocabulary: &V,
170		ty: LiteralTypeRef<'a, V::Iri>,
171	) -> CowRdfLiteral<'a, V> {
172		self.as_str().as_rdf_literal(vocabulary, ty)
173	}
174}
175
176pub trait RdfLiteralType<V: IriVocabulary>: From<rdf_types::LiteralType<V::Iri>> {}
177
178impl<V: IriVocabulary, T: From<rdf_types::LiteralType<V::Iri>>> RdfLiteralType<V> for T {}
179
180#[derive(Educe)]
181#[educe(Debug(bound = "V::Iri: fmt::Debug"))]
182pub enum RdfLiteral<V: IriVocabulary> {
183	Any(String, rdf_types::LiteralType<V::Iri>),
184	Xsd(xsd_types::Value),
185	Json(json_syntax::Value),
186}
187
188impl<V: IriVocabulary> RdfLiteral<V> {
189	pub fn into_lexical(self, vocabulary: &V) -> rdf_types::Literal {
190		match self {
191			Self::Any(s, LiteralType::Any(ty)) => rdf_types::Literal::new(
192				s.to_owned(),
193				LiteralType::Any(vocabulary.owned_iri(ty).ok().unwrap()),
194			),
195			Self::Any(s, LiteralType::LangString(lang)) => {
196				rdf_types::Literal::new(s.to_owned(), LiteralType::LangString(lang))
197			}
198			Self::Xsd(value) => {
199				let ty = value.datatype().iri().to_owned();
200				rdf_types::Literal::new(value.to_string(), LiteralType::Any(ty))
201			}
202			Self::Json(mut value) => {
203				value.canonicalize();
204				rdf_types::Literal::new(value.to_string(), LiteralType::Any(RDF_JSON.to_owned()))
205			}
206		}
207	}
208
209	pub fn as_literal_ref(&self) -> RdfLiteralRef<V> {
210		match self {
211			Self::Any(value, ty) => RdfLiteralRef::Any(value, ty.as_ref()),
212			Self::Xsd(value) => RdfLiteralRef::Xsd(value.as_ref()),
213			Self::Json(value) => RdfLiteralRef::Json(value),
214		}
215	}
216}
217
218impl<V: IriVocabulary> fmt::Display for RdfLiteral<V> {
219	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220		match self {
221			Self::Any(v, _) => v.fmt(f),
222			Self::Xsd(v) => v.fmt(f),
223			Self::Json(v) => v.fmt(f),
224		}
225	}
226}
227
228const RDF_JSON: &Iri = static_iref::iri!("http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON");
229
230impl<V: Vocabulary + IriVocabularyMut + LiteralVocabularyMut> EmbedIntoVocabulary<V>
231	for RdfLiteral<V>
232{
233	type Embedded = V::Literal;
234
235	fn embed_into_vocabulary(self, vocabulary: &mut V) -> V::Literal {
236		match self {
237			Self::Any(s, ty) => vocabulary.insert_owned_literal(rdf_types::Literal::new(s, ty)),
238			Self::Xsd(v) => {
239				let ty = rdf_types::LiteralType::Any(vocabulary.insert(v.datatype().iri()));
240				vocabulary.insert_owned_literal(rdf_types::Literal::new(v.into(), ty))
241			}
242			Self::Json(v) => {
243				let ty = rdf_types::LiteralType::Any(vocabulary.insert(RDF_JSON));
244				vocabulary.insert_owned_literal(rdf_types::Literal::new(v.into(), ty))
245			}
246		}
247	}
248}
249
250#[derive(Educe)]
251#[educe(Debug(bound = "V::Iri: fmt::Debug"), Clone, Copy)]
252pub enum RdfLiteralRef<'a, V: IriVocabulary = ()> {
253	Any(&'a str, rdf_types::LiteralTypeRef<'a, V::Iri>),
254	Xsd(xsd_types::ValueRef<'a>),
255	Json(&'a json_syntax::Value),
256}
257
258impl<V: IriVocabulary> RdfLiteralRef<'_, V> {
259	pub fn into_lexical(self, vocabulary: &V) -> rdf_types::Literal {
260		match self {
261			Self::Any(s, LiteralTypeRef::Any(ty)) => rdf_types::Literal::new(
262				s.to_owned(),
263				LiteralType::Any(vocabulary.iri(ty).unwrap().to_owned()),
264			),
265			Self::Any(s, LiteralTypeRef::LangString(lang)) => {
266				rdf_types::Literal::new(s.to_owned(), LiteralType::LangString(lang.to_owned()))
267			}
268			Self::Xsd(value) => {
269				let ty = value.datatype().iri().to_owned();
270				rdf_types::Literal::new(value.to_string(), LiteralType::Any(ty))
271			}
272			Self::Json(value) => {
273				let mut value = value.clone();
274				value.canonicalize();
275				rdf_types::Literal::new(value.to_string(), LiteralType::Any(RDF_JSON.to_owned()))
276			}
277		}
278	}
279
280	pub fn into_owned(self) -> RdfLiteral<V>
281	where
282		V::Iri: Clone,
283	{
284		match self {
285			Self::Any(value, ty) => RdfLiteral::Any(value.to_owned(), ty.into_owned()),
286			Self::Xsd(value) => RdfLiteral::Xsd(value.into_owned()),
287			Self::Json(value) => RdfLiteral::Json(value.clone()),
288		}
289	}
290}
291
292pub enum CowRdfLiteral<'a, V: IriVocabulary = ()> {
293	Borrowed(RdfLiteralRef<'a, V>),
294	Owned(RdfLiteral<V>),
295}
296
297impl<V: IriVocabulary> CowRdfLiteral<'_, V> {
298	pub fn into_owned(self) -> RdfLiteral<V>
299	where
300		V::Iri: Clone,
301	{
302		match self {
303			Self::Borrowed(l) => l.into_owned(),
304			Self::Owned(l) => l,
305		}
306	}
307
308	pub fn as_literal_ref(&self) -> RdfLiteralRef<V> {
309		match self {
310			Self::Borrowed(l) => *l,
311			Self::Owned(l) => l.as_literal_ref(),
312		}
313	}
314}