1use educe::Educe;
51use iri_rs::{Iri, IriBuf};
52#[cfg(feature = "derive")]
53pub use ld_core_derive::{Deserialize, Serialize};
54use rdfx::{
55 Interpretation, dataset::PatternMatchingDataset, interpretation::ReverseInterpretation,
56};
57
58#[doc(hidden)]
59pub use iri_rs;
60
61#[doc(hidden)]
62pub use rdfx;
63
64#[doc(hidden)]
65pub use xsd_rs;
66
67#[doc(hidden)]
68pub use jstrict;
69
70mod anonymous;
71mod datatypes;
72mod graph;
73mod r#impl;
74mod macros;
75mod predicate;
76mod quads;
77mod rdf;
78mod reference;
79mod resource;
80mod subject;
81
82pub use anonymous::*;
83pub use graph::*;
84pub use predicate::*;
85pub use quads::{
86 IntoQuadsError, to_interpreted_graph_quads, to_interpreted_quads, to_interpreted_subject_quads,
87 to_lexical_quads, to_lexical_quads_with, to_lexical_subject_quads,
88 to_lexical_subject_quads_with, to_quads, to_quads_with,
89};
90pub use rdf::*;
91pub use reference::*;
92pub use resource::*;
93pub use subject::*;
94
95#[derive(Debug, thiserror::Error)]
96pub enum FromLinkedDataError {
98 #[error("expected IRI")]
100 ExpectedIri(ContextIris),
101
102 #[error("unsupported IRI `{found}`")]
103 UnsupportedIri {
105 context: ContextIris,
107
108 found: IriBuf,
110
111 supported: Option<Vec<IriBuf>>,
113 },
114
115 #[error("expected literal")]
117 ExpectedLiteral(ContextIris),
118
119 #[error("literal type mismatch")]
125 LiteralTypeMismatch {
126 context: ContextIris,
128 expected: Option<Box<IriBuf>>,
130 found: Box<IriBuf>,
132 },
133
134 #[error("invalid literal")]
137 InvalidLiteral(ContextIris),
138
139 #[error("missing required value")]
141 MissingRequiredValue(ContextIris),
142
143 #[error("too many values")]
145 TooManyValues(ContextIris),
146
147 #[error("invalid subject")]
149 InvalidSubject {
150 context: ContextIris,
152 subject: Option<IriBuf>,
154 },
155}
156
157impl FromLinkedDataError {
158 pub fn context(&self) -> &ContextIris {
160 match self {
161 Self::ExpectedIri(c) => c,
162 Self::UnsupportedIri { context, .. } => context,
163 Self::ExpectedLiteral(c) => c,
164 Self::LiteralTypeMismatch { context, .. } => context,
165 Self::InvalidLiteral(c) => c,
166 Self::MissingRequiredValue(c) => c,
167 Self::TooManyValues(c) => c,
168 Self::InvalidSubject { context, .. } => context,
169 }
170 }
171}
172
173pub trait LinkedData<I: Interpretation = ()> {
178 fn visit<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
180 where
181 S: Visitor<I>;
182}
183
184impl<I: Interpretation, T: ?Sized + LinkedData<I>> LinkedData<I> for &T {
185 fn visit<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
186 where
187 S: Visitor<I>,
188 {
189 T::visit(self, visitor)
190 }
191}
192
193impl<I: Interpretation, T: ?Sized + LinkedData<I>> LinkedData<I> for Box<T> {
194 fn visit<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
195 where
196 S: Visitor<I>,
197 {
198 T::visit(self, visitor)
199 }
200}
201
202impl<I: Interpretation> LinkedData<I> for IriBuf {
203 fn visit<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
204 where
205 S: Visitor<I>,
206 {
207 visitor.end()
208 }
209}
210
211pub trait Visitor<I: Interpretation = ()> {
213 type Ok;
216
217 type Error;
219
220 fn default_graph<T>(&mut self, value: &T) -> Result<(), Self::Error>
222 where
223 T: ?Sized + LinkedDataGraph<I>;
224
225 fn named_graph<T>(&mut self, value: &T) -> Result<(), Self::Error>
227 where
228 T: ?Sized + LinkedDataResource<I> + LinkedDataGraph<I>;
229
230 fn end(self) -> Result<Self::Ok, Self::Error>;
232}
233
234impl<I: Interpretation, S: Visitor<I>> Visitor<I> for &mut S {
236 type Ok = ();
237 type Error = S::Error;
238
239 fn default_graph<T>(&mut self, value: &T) -> Result<(), Self::Error>
240 where
241 T: ?Sized + LinkedDataGraph<I>,
242 {
243 S::default_graph(self, value)
244 }
245
246 fn named_graph<T>(&mut self, value: &T) -> Result<(), Self::Error>
247 where
248 T: ?Sized + LinkedDataResource<I> + LinkedDataGraph<I>,
249 {
250 S::named_graph(self, value)
251 }
252
253 fn end(self) -> Result<Self::Ok, Self::Error> {
254 Ok(())
255 }
256}
257
258#[derive(Educe)]
259#[educe(Debug(bound = "I::Resource: core::fmt::Debug"), Clone, Copy)]
260pub enum ResourceOrIriRef<'a, I: Interpretation> {
262 Resource(&'a I::Resource),
264 Iri(Iri<&'a str>),
266 Anonymous,
268}
269
270impl<'a, I: Interpretation> ResourceOrIriRef<'a, I> {
271 pub fn into_iri(self, interpretation: &I) -> Option<IriBuf>
273 where
274 I: ReverseInterpretation,
275 {
276 match self {
277 Self::Resource(r) => interpretation.iris_of(r).next().map(|i| i.into_owned()),
278 Self::Iri(i) => Some(i.into()),
279 Self::Anonymous => None,
280 }
281 }
282}
283
284#[derive(Educe)]
285#[educe(Debug(bound = "I::Resource: core::fmt::Debug"), Clone, Copy)]
286#[derive(Default)]
288pub enum Context<'a, I: Interpretation> {
289 #[default]
291 Subject,
292 Predicate {
294 subject: ResourceOrIriRef<'a, I>,
296 },
297 Object {
299 subject: ResourceOrIriRef<'a, I>,
301 predicate: ResourceOrIriRef<'a, I>,
303 },
304}
305
306impl<'a, I: Interpretation> Context<'a, I> {
307 pub fn with_subject(self, subject: &'a I::Resource) -> Self {
309 Self::Predicate {
310 subject: ResourceOrIriRef::Resource(subject),
311 }
312 }
313
314 pub fn with_predicate(self, predicate: &'a I::Resource) -> Self {
316 match self {
317 Self::Predicate { subject } => Self::Object {
318 subject,
319 predicate: ResourceOrIriRef::Resource(predicate),
320 },
321 _ => Self::Subject,
322 }
323 }
324
325 pub fn with_predicate_iri(self, predicate: Iri<&'a str>) -> Self {
327 match self {
328 Self::Predicate { subject } => Self::Object {
329 subject,
330 predicate: ResourceOrIriRef::Iri(predicate),
331 },
332 _ => Self::Subject,
333 }
334 }
335
336 pub fn with_anonymous_predicate(self) -> Self {
338 match self {
339 Self::Predicate { subject } => Self::Object {
340 subject,
341 predicate: ResourceOrIriRef::Anonymous,
342 },
343 _ => Self::Subject,
344 }
345 }
346
347 pub fn into_iris(self, interpretation: &I) -> ContextIris
349 where
350 I: ReverseInterpretation,
351 {
352 match self {
353 Self::Subject => ContextIris::Subject,
354 Self::Predicate { subject } => ContextIris::Predicate {
355 subject: subject.into_iri(interpretation).map(Box::new),
356 },
357 Self::Object { subject, predicate } => ContextIris::Object {
358 subject: subject.into_iri(interpretation).map(Box::new),
359 predicate: predicate.into_iri(interpretation).map(Box::new),
360 },
361 }
362 }
363}
364
365#[derive(Debug, Clone)]
366pub enum ContextIris {
374 Subject,
376 Predicate {
378 subject: Option<Box<IriBuf>>,
380 },
381 Object {
383 subject: Option<Box<IriBuf>>,
385 predicate: Option<Box<IriBuf>>,
387 },
388}
389
390pub trait LinkedDataDeserialize<I: Interpretation>: Sized
392where
393 I::Resource: rdfx::Resource,
394{
395 fn deserialize_dataset_in(
398 interpretation: &I,
399 dataset: &(
400 impl rdfx::dataset::TraversableDataset<Subject = I::Resource>
401 + PatternMatchingDataset<Subject = I::Resource>
402 ),
403 context: Context<I>,
404 ) -> Result<Self, FromLinkedDataError>;
405
406 fn deserialize_dataset(
408 interpretation: &I,
409 dataset: &(
410 impl rdfx::dataset::TraversableDataset<Subject = I::Resource>
411 + PatternMatchingDataset<Subject = I::Resource>
412 ),
413 ) -> Result<Self, FromLinkedDataError> {
414 Self::deserialize_dataset_in(interpretation, dataset, Context::default())
415 }
416}