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}