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")]
121 LiteralTypeMismatch {
122 context: ContextIris,
124 expected: Option<IriBuf>,
126 found: IriBuf,
128 },
129
130 #[error("invalid literal")]
133 InvalidLiteral(ContextIris),
134
135 #[error("missing required value")]
137 MissingRequiredValue(ContextIris),
138
139 #[error("too many values")]
141 TooManyValues(ContextIris),
142
143 #[error("invalid subject")]
145 InvalidSubject {
146 context: ContextIris,
148 subject: Option<IriBuf>,
150 },
151}
152
153impl FromLinkedDataError {
154 pub fn context(&self) -> &ContextIris {
156 match self {
157 Self::ExpectedIri(c) => c,
158 Self::UnsupportedIri { context, .. } => context,
159 Self::ExpectedLiteral(c) => c,
160 Self::LiteralTypeMismatch { context, .. } => context,
161 Self::InvalidLiteral(c) => c,
162 Self::MissingRequiredValue(c) => c,
163 Self::TooManyValues(c) => c,
164 Self::InvalidSubject { context, .. } => context,
165 }
166 }
167}
168
169pub trait LinkedData<I: Interpretation = ()> {
174 fn visit<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
176 where
177 S: Visitor<I>;
178}
179
180impl<I: Interpretation, T: ?Sized + LinkedData<I>> LinkedData<I> for &T {
181 fn visit<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
182 where
183 S: Visitor<I>,
184 {
185 T::visit(self, visitor)
186 }
187}
188
189impl<I: Interpretation, T: ?Sized + LinkedData<I>> LinkedData<I> for Box<T> {
190 fn visit<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
191 where
192 S: Visitor<I>,
193 {
194 T::visit(self, visitor)
195 }
196}
197
198impl<I: Interpretation> LinkedData<I> for IriBuf {
199 fn visit<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
200 where
201 S: Visitor<I>,
202 {
203 visitor.end()
204 }
205}
206
207pub trait Visitor<I: Interpretation = ()> {
209 type Ok;
212
213 type Error;
215
216 fn default_graph<T>(&mut self, value: &T) -> Result<(), Self::Error>
218 where
219 T: ?Sized + LinkedDataGraph<I>;
220
221 fn named_graph<T>(&mut self, value: &T) -> Result<(), Self::Error>
223 where
224 T: ?Sized + LinkedDataResource<I> + LinkedDataGraph<I>;
225
226 fn end(self) -> Result<Self::Ok, Self::Error>;
228}
229
230impl<I: Interpretation, S: Visitor<I>> Visitor<I> for &mut S {
232 type Ok = ();
233 type Error = S::Error;
234
235 fn default_graph<T>(&mut self, value: &T) -> Result<(), Self::Error>
236 where
237 T: ?Sized + LinkedDataGraph<I>,
238 {
239 S::default_graph(self, value)
240 }
241
242 fn named_graph<T>(&mut self, value: &T) -> Result<(), Self::Error>
243 where
244 T: ?Sized + LinkedDataResource<I> + LinkedDataGraph<I>,
245 {
246 S::named_graph(self, value)
247 }
248
249 fn end(self) -> Result<Self::Ok, Self::Error> {
250 Ok(())
251 }
252}
253
254#[derive(Educe)]
255#[educe(Debug(bound = "I::Resource: core::fmt::Debug"), Clone, Copy)]
256pub enum ResourceOrIriRef<'a, I: Interpretation> {
258 Resource(&'a I::Resource),
260 Iri(Iri<&'a str>),
262 Anonymous,
264}
265
266impl<'a, I: Interpretation> ResourceOrIriRef<'a, I> {
267 pub fn into_iri(self, interpretation: &I) -> Option<IriBuf>
269 where
270 I: ReverseInterpretation,
271 {
272 match self {
273 Self::Resource(r) => interpretation.iris_of(r).next().map(|i| i.into_owned()),
274 Self::Iri(i) => Some(i.into()),
275 Self::Anonymous => None,
276 }
277 }
278}
279
280#[derive(Educe)]
281#[educe(Debug(bound = "I::Resource: core::fmt::Debug"), Clone, Copy)]
282#[derive(Default)]
284pub enum Context<'a, I: Interpretation> {
285 #[default]
287 Subject,
288 Predicate {
290 subject: ResourceOrIriRef<'a, I>,
292 },
293 Object {
295 subject: ResourceOrIriRef<'a, I>,
297 predicate: ResourceOrIriRef<'a, I>,
299 },
300}
301
302impl<'a, I: Interpretation> Context<'a, I> {
303 pub fn with_subject(self, subject: &'a I::Resource) -> Self {
305 Self::Predicate {
306 subject: ResourceOrIriRef::Resource(subject),
307 }
308 }
309
310 pub fn with_predicate(self, predicate: &'a I::Resource) -> Self {
312 match self {
313 Self::Predicate { subject } => Self::Object {
314 subject,
315 predicate: ResourceOrIriRef::Resource(predicate),
316 },
317 _ => Self::Subject,
318 }
319 }
320
321 pub fn with_predicate_iri(self, predicate: Iri<&'a str>) -> Self {
323 match self {
324 Self::Predicate { subject } => Self::Object {
325 subject,
326 predicate: ResourceOrIriRef::Iri(predicate),
327 },
328 _ => Self::Subject,
329 }
330 }
331
332 pub fn with_anonymous_predicate(self) -> Self {
334 match self {
335 Self::Predicate { subject } => Self::Object {
336 subject,
337 predicate: ResourceOrIriRef::Anonymous,
338 },
339 _ => Self::Subject,
340 }
341 }
342
343 pub fn into_iris(self, interpretation: &I) -> ContextIris
345 where
346 I: ReverseInterpretation,
347 {
348 match self {
349 Self::Subject => ContextIris::Subject,
350 Self::Predicate { subject } => ContextIris::Predicate {
351 subject: subject.into_iri(interpretation),
352 },
353 Self::Object { subject, predicate } => ContextIris::Object {
354 subject: subject.into_iri(interpretation),
355 predicate: predicate.into_iri(interpretation),
356 },
357 }
358 }
359}
360
361#[derive(Debug, Clone)]
362pub enum ContextIris {
364 Subject,
366 Predicate {
368 subject: Option<IriBuf>,
370 },
371 Object {
373 subject: Option<IriBuf>,
375 predicate: Option<IriBuf>,
377 },
378}
379
380pub trait LinkedDataDeserialize<I: Interpretation>: Sized
382where
383 I::Resource: rdfx::Resource,
384{
385 fn deserialize_dataset_in(
388 interpretation: &I,
389 dataset: &(
390 impl rdfx::dataset::TraversableDataset<Subject = I::Resource>
391 + PatternMatchingDataset<Subject = I::Resource>
392 ),
393 context: Context<I>,
394 ) -> Result<Self, FromLinkedDataError>;
395
396 fn deserialize_dataset(
398 interpretation: &I,
399 dataset: &(
400 impl rdfx::dataset::TraversableDataset<Subject = I::Resource>
401 + PatternMatchingDataset<Subject = I::Resource>
402 ),
403 ) -> Result<Self, FromLinkedDataError> {
404 Self::deserialize_dataset_in(interpretation, dataset, Context::default())
405 }
406}