json_ld/processor/mod.rs
1use crate::compaction::{self, Compact};
2use crate::context_processing::{self, Process};
3use crate::expansion;
4use crate::syntax::ErrorCode;
5use crate::{flattening::ConflictingIndexes, Context, ExpandedDocument, Loader, ProcessingMode};
6use iref::IriBuf;
7use json_ld_core::rdf::RdfDirection;
8use json_ld_core::{ContextLoadError, LoadError};
9use json_ld_core::{Document, RdfQuads, RemoteContextReference};
10use rdf_types::{vocabulary, BlankIdBuf, Generator, Vocabulary, VocabularyMut};
11use std::hash::Hash;
12
13mod remote_document;
14
15/// JSON-LD Processor options.
16#[derive(Clone)]
17pub struct Options<I = IriBuf> {
18 /// The base IRI to use when expanding or compacting the document.
19 ///
20 /// If set, this overrides the input document's IRI.
21 pub base: Option<I>,
22
23 /// If set to true, the JSON-LD processor replaces arrays with just one element with that element during compaction.
24 ///
25 /// If set to false, all arrays will remain arrays even if they have just one element.
26 ///
27 /// Defaults to `true`.
28 pub compact_arrays: bool,
29
30 /// Determines if IRIs are compacted relative to the base option or document
31 /// location when compacting.
32 ///
33 /// Defaults to `true`.
34 pub compact_to_relative: bool,
35
36 /// A context that is used to initialize the active context when expanding a document.
37 pub expand_context: Option<RemoteContextReference<I>>,
38
39 /// If set to `true`, certain algorithm processing steps where indicated are
40 /// ordered lexicographically.
41 ///
42 /// If `false`, order is not considered in processing.
43 ///
44 /// Defaults to `false`.
45 pub ordered: bool,
46
47 /// Sets the processing mode.
48 ///
49 /// Defaults to `ProcessingMode::JsonLd1_1`.
50 pub processing_mode: ProcessingMode,
51
52 /// Determines how value objects containing a base direction are transformed
53 /// to and from RDF.
54 ///
55 /// - If set to [`RdfDirection::I18nDatatype`], an RDF literal is
56 /// generated using a datatype IRI based on
57 /// <https://www.w3.org/ns/i18n#> with both the language tag (if
58 /// present) and base direction encoded. When transforming from RDF,
59 /// this datatype is decoded to create a value object containing
60 /// `@language` (if present) and `@direction`.
61 /// - If set to [`RdfDirection::CompoundLiteral`], a blank node is emitted
62 /// instead of a literal, where the blank node is the subject of
63 /// `rdf:value`, `rdf:direction`, and `rdf:language` (if present)
64 /// properties. When transforming from RDF, this object is decoded to
65 /// create a value object containing `@language` (if present) and
66 /// `@direction`.
67 pub rdf_direction: Option<RdfDirection>,
68
69 /// If set to `true`, the JSON-LD processor may emit blank nodes for triple
70 /// predicates, otherwise they will be omitted.
71 /// See <https://www.w3.org/TR/rdf11-concepts/>.
72 ///
73 /// The use of blank node identifiers to label properties is obsolete, and
74 /// may be removed in a future version of JSON-LD, as is the support for
75 /// generalized RDF Datasets and thus this option
76 /// may be also be removed.
77 pub produce_generalized_rdf: bool,
78
79 /// Term expansion policy, passed to the document expansion algorithm.
80 pub expansion_policy: expansion::Policy,
81}
82
83impl<I> Options<I> {
84 /// Returns these options with the `ordered` flag set to `false`.
85 ///
86 /// This means entries will not be ordered by keys before being processed.
87 pub fn unordered(self) -> Self {
88 Self {
89 ordered: false,
90 ..self
91 }
92 }
93
94 /// Returns these options with the `expand_context` set to the given
95 /// `context`.
96 pub fn with_expand_context(self, context: RemoteContextReference<I>) -> Self {
97 Self {
98 expand_context: Some(context),
99 ..self
100 }
101 }
102
103 /// Builds options for the context processing algorithm from these options.
104 pub fn context_processing_options(&self) -> context_processing::Options {
105 context_processing::Options {
106 processing_mode: self.processing_mode,
107 ..Default::default()
108 }
109 }
110
111 /// Builds options for the expansion algorithm from these options.
112 pub fn expansion_options(&self) -> expansion::Options {
113 expansion::Options {
114 processing_mode: self.processing_mode,
115 ordered: self.ordered,
116 policy: self.expansion_policy,
117 }
118 }
119
120 /// Builds options for the compaction algorithm from these options.
121 pub fn compaction_options(&self) -> compaction::Options {
122 compaction::Options {
123 processing_mode: self.processing_mode,
124 compact_to_relative: self.compact_to_relative,
125 compact_arrays: self.compact_arrays,
126 ordered: self.ordered,
127 }
128 }
129}
130
131impl<I> Default for Options<I> {
132 fn default() -> Self {
133 Self {
134 base: None,
135 compact_arrays: true,
136 compact_to_relative: true,
137 expand_context: None,
138 ordered: false,
139 processing_mode: ProcessingMode::JsonLd1_1,
140 rdf_direction: None,
141 produce_generalized_rdf: false,
142 expansion_policy: expansion::Policy::default(),
143 }
144 }
145}
146
147/// Error that can be raised by the [`JsonLdProcessor::expand`] function.
148#[derive(Debug, thiserror::Error)]
149pub enum ExpandError {
150 /// Document expansion failed.
151 #[error("Expansion failed: {0}")]
152 Expansion(expansion::Error),
153
154 /// Context processing failed.
155 #[error("Context processing failed: {0}")]
156 ContextProcessing(context_processing::Error),
157
158 /// Remote document loading failed with the given precise error.
159 #[error(transparent)]
160 Loading(#[from] LoadError),
161
162 #[error(transparent)]
163 ContextLoading(ContextLoadError),
164}
165
166impl ExpandError {
167 /// Returns the code of this error.
168 pub fn code(&self) -> ErrorCode {
169 match self {
170 Self::Expansion(e) => e.code(),
171 Self::ContextProcessing(e) => e.code(),
172 Self::Loading(_) => ErrorCode::LoadingDocumentFailed,
173 Self::ContextLoading(_) => ErrorCode::LoadingRemoteContextFailed,
174 }
175 }
176}
177
178/// Result returned by the [`JsonLdProcessor::expand`] function.
179pub type ExpandResult<I, B> = Result<ExpandedDocument<I, B>, ExpandError>;
180
181/// Result returned by the [`JsonLdProcessor::into_document`] function.
182pub type IntoDocumentResult<I, B> = Result<Document<I, B>, ExpandError>;
183
184/// Error that can be raised by the [`JsonLdProcessor::compact`] function.
185#[derive(Debug, thiserror::Error)]
186pub enum CompactError {
187 /// Document expansion failed.
188 #[error("Expansion failed: {0}")]
189 Expand(ExpandError),
190
191 /// Context processing failed.
192 #[error("Context processing failed: {0}")]
193 ContextProcessing(context_processing::Error),
194
195 /// Document compaction failed.
196 #[error("Compaction failed: {0}")]
197 Compaction(compaction::Error),
198
199 /// Remote document loading failed.
200 #[error(transparent)]
201 Loading(#[from] LoadError),
202
203 #[error(transparent)]
204 ContextLoading(ContextLoadError),
205}
206
207impl CompactError {
208 /// Returns the code of this error.
209 pub fn code(&self) -> ErrorCode {
210 match self {
211 Self::Expand(e) => e.code(),
212 Self::ContextProcessing(e) => e.code(),
213 Self::Compaction(e) => e.code(),
214 Self::Loading(_) => ErrorCode::LoadingDocumentFailed,
215 Self::ContextLoading(_) => ErrorCode::LoadingRemoteContextFailed,
216 }
217 }
218}
219
220/// Result of the [`JsonLdProcessor::compact`] function.
221pub type CompactResult = Result<json_syntax::Value, CompactError>;
222
223/// Error that can be raised by the [`JsonLdProcessor::flatten`] function.
224#[derive(Debug, thiserror::Error)]
225pub enum FlattenError<I, B> {
226 #[error("Expansion failed: {0}")]
227 Expand(ExpandError),
228
229 #[error("Compaction failed: {0}")]
230 Compact(CompactError),
231
232 #[error("Conflicting indexes: {0}")]
233 ConflictingIndexes(ConflictingIndexes<I, B>),
234
235 #[error(transparent)]
236 Loading(#[from] LoadError),
237
238 #[error(transparent)]
239 ContextLoading(ContextLoadError),
240}
241
242impl<I, B> FlattenError<I, B> {
243 /// Returns the code of this error.
244 pub fn code(&self) -> ErrorCode {
245 match self {
246 Self::Expand(e) => e.code(),
247 Self::Compact(e) => e.code(),
248 Self::ConflictingIndexes(_) => ErrorCode::ConflictingIndexes,
249 Self::Loading(_) => ErrorCode::LoadingDocumentFailed,
250 Self::ContextLoading(_) => ErrorCode::LoadingRemoteContextFailed,
251 }
252 }
253}
254
255/// Result of the [`JsonLdProcessor::flatten`] function.
256pub type FlattenResult<I, B> = Result<json_syntax::Value, FlattenError<I, B>>;
257
258/// Error that can be raised by the [`JsonLdProcessor::to_rdf`] function.
259#[derive(Debug, thiserror::Error)]
260pub enum ToRdfError {
261 /// Document expansion failed.
262 #[error("Expansion failed: {0}")]
263 Expand(ExpandError),
264}
265
266impl ToRdfError {
267 /// Returns the code of this error.
268 pub fn code(&self) -> ErrorCode {
269 match self {
270 Self::Expand(e) => e.code(),
271 }
272 }
273}
274
275/// Error that can be raised by the [`JsonLdProcessor::to_rdf`] function.
276pub type ToRdfResult<V, G> = Result<ToRdf<V, G>, ToRdfError>;
277
278/// Result of the [`JsonLdProcessor::compare`] function.
279pub type CompareResult = Result<bool, ExpandError>;
280
281/// Application Programming Interface.
282///
283/// The `JsonLdProcessor` interface is the high-level programming structure that
284/// developers use to access the JSON-LD transformation methods.
285///
286/// It is notably implemented for the [`RemoteDocument<I, M, json_syntax::Value<M>>`](crate::RemoteDocument)
287/// and [`RemoteDocumentReference<I, M, json_syntax::Value<M>>`] types.
288///
289/// # Methods naming
290///
291/// Each processing function is declined in four variants depending on your
292/// needs, with the following suffix convention:
293///
294/// - `_full`: function with all the possible options. This is the only way
295/// to specify a custom warning handler.
296/// - `_with`: allows passing a custom [`Vocabulary`].
297/// - `_using`: allows passing custom [`Options`].
298/// - `_with_using`: allows passing both a custom [`Vocabulary`] and
299/// custom [`Options`].
300/// - no suffix: minimum parameters. No custom vocabulary: [`IriBuf`] and
301/// [`BlankIdBuf`] must be used as IRI and blank node id respectively.
302///
303/// [`IriBuf`]: https://docs.rs/iref/latest/iref/struct.IriBuf.html
304/// [`BlankIdBuf`]: rdf_types::BlankIdBuf
305/// [`Vocabulary`]: rdf_types::Vocabulary
306///
307/// # Example
308///
309/// ```
310/// use static_iref::iri;
311/// use json_ld::{JsonLdProcessor, RemoteDocumentReference};
312///
313/// # #[async_std::main]
314/// # async fn main() {
315/// let input = RemoteDocumentReference::iri(iri!("https://example.com/sample.jsonld").to_owned());
316///
317/// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
318/// // the local `example` directory. No HTTP query.
319/// let mut loader = json_ld::FsLoader::default();
320/// loader.mount(iri!("https://example.com/").to_owned(), "examples");
321///
322/// let expanded = input.expand(&loader)
323/// .await
324/// .expect("expansion failed");
325/// # }
326/// ```
327pub trait JsonLdProcessor<Iri>: Sized {
328 /// Compare this document against `other` with a custom vocabulary using the
329 /// given `options` and warnings handler.
330 ///
331 /// # Example
332 ///
333 /// ```
334 /// use static_iref::iri;
335 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
336 /// use rdf_types::vocabulary::{IriVocabularyMut, IndexVocabulary};
337 ///
338 /// # #[async_std::main]
339 /// # async fn main() {
340 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
341 ///
342 /// let iri = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
343 /// let input1 = RemoteDocumentReference::iri(iri);
344 /// let input2 = RemoteDocumentReference::iri(iri);
345 ///
346 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
347 /// // the local `example` directory. No HTTP query.
348 /// let mut loader = json_ld::FsLoader::default();
349 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
350 ///
351 /// assert!(input1.compare_full(
352 /// &input2,
353 /// &mut vocabulary,
354 /// &loader,
355 /// Options::default(),
356 /// warning::PrintWith
357 /// ).await.expect("comparison failed"));
358 /// # }
359 /// ```
360 #[allow(async_fn_in_trait)]
361 async fn compare_full<N>(
362 &self,
363 other: &Self,
364 vocabulary: &mut N,
365 loader: &impl Loader,
366 options: Options<Iri>,
367 warnings: impl context_processing::WarningHandler<N> + expansion::WarningHandler<N>,
368 ) -> CompareResult
369 where
370 N: VocabularyMut<Iri = Iri>,
371 Iri: Clone + Eq + Hash,
372 N::BlankId: Clone + Eq + Hash;
373
374 /// Compare this document against `other` with a custom vocabulary using the
375 /// given `options`.
376 ///
377 /// Warnings are ignored.
378 ///
379 /// # Example
380 ///
381 /// ```
382 /// use static_iref::iri;
383 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference};
384 /// use rdf_types::vocabulary::{IriVocabularyMut, IndexVocabulary};
385 ///
386 /// # #[async_std::main]
387 /// # async fn main() {
388 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
389 ///
390 /// let iri = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
391 /// let input1 = RemoteDocumentReference::iri(iri);
392 /// let input2 = RemoteDocumentReference::iri(iri);
393 ///
394 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
395 /// // the local `example` directory. No HTTP query.
396 /// let mut loader = json_ld::FsLoader::default();
397 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
398 ///
399 /// assert!(input1.compare_with_using(
400 /// &input2,
401 /// &mut vocabulary,
402 /// &loader,
403 /// Options::default()
404 /// ).await.expect("comparison failed"));
405 /// # }
406 /// ```
407 #[allow(async_fn_in_trait)]
408 async fn compare_with_using<'a, N>(
409 &'a self,
410 other: &'a Self,
411 vocabulary: &'a mut N,
412 loader: &'a impl Loader,
413 options: Options<Iri>,
414 ) -> CompareResult
415 where
416 N: VocabularyMut<Iri = Iri>,
417 Iri: Clone + Eq + Hash,
418 N::BlankId: 'a + Clone + Eq + Hash,
419 {
420 self.compare_full(other, vocabulary, loader, options, ())
421 .await
422 }
423
424 /// Compare this document against `other` with a custom vocabulary.
425 ///
426 /// Default options are used.
427 /// Warnings are ignored.
428 ///
429 /// # Example
430 ///
431 /// ```
432 /// use static_iref::iri;
433 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference};
434 /// use rdf_types::vocabulary::{IriVocabularyMut, IndexVocabulary};
435 /// use locspan::Meta;
436 ///
437 /// # #[async_std::main]
438 /// # async fn main() {
439 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
440 ///
441 /// let iri = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
442 /// let input1 = RemoteDocumentReference::iri(iri);
443 /// let input2 = RemoteDocumentReference::iri(iri);
444 ///
445 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
446 /// // the local `example` directory. No HTTP query.
447 /// let mut loader = json_ld::FsLoader::default();
448 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
449 ///
450 /// assert!(input1.compare_with(
451 /// &input2,
452 /// &mut vocabulary,
453 /// &loader
454 /// ).await.expect("comparison failed"));
455 /// # }
456 /// ```
457 #[allow(async_fn_in_trait)]
458 async fn compare_with<'a, N>(
459 &'a self,
460 other: &'a Self,
461 vocabulary: &'a mut N,
462 loader: &'a impl Loader,
463 ) -> CompareResult
464 where
465 N: VocabularyMut<Iri = Iri>,
466 Iri: Clone + Eq + Hash,
467 N::BlankId: 'a + Clone + Eq + Hash,
468 {
469 self.compare_with_using(other, vocabulary, loader, Options::default())
470 .await
471 }
472
473 /// Compare this document against `other` using the given `options`.
474 ///
475 /// Warnings are ignored.
476 ///
477 /// # Example
478 ///
479 /// ```
480 /// use static_iref::iri;
481 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference};
482 /// use locspan::Meta;
483 ///
484 /// # #[async_std::main]
485 /// # async fn main() {
486 /// let iri = iri!("https://example.com/sample.jsonld").to_owned();
487 /// let input1 = RemoteDocumentReference::iri(iri.clone());
488 /// let input2 = RemoteDocumentReference::iri(iri);
489 ///
490 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
491 /// // the local `example` directory. No HTTP query.
492 /// let mut loader = json_ld::FsLoader::default();
493 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
494 ///
495 /// assert!(input1.compare_using(
496 /// &input2,
497 /// &loader,
498 /// Options::default()
499 /// ).await.expect("comparison failed"));
500 /// # }
501 /// ```
502 #[allow(async_fn_in_trait)]
503 async fn compare_using<'a>(
504 &'a self,
505 other: &'a Self,
506 loader: &'a impl Loader,
507 options: Options<Iri>,
508 ) -> CompareResult
509 where
510 (): VocabularyMut<Iri = Iri>,
511 Iri: Clone + Eq + Hash,
512 {
513 self.compare_with_using(
514 other,
515 rdf_types::vocabulary::no_vocabulary_mut(),
516 loader,
517 options,
518 )
519 .await
520 }
521
522 /// Compare this document against `other` with a custom vocabulary.
523 ///
524 /// Default options are used.
525 /// Warnings are ignored.
526 ///
527 /// # Example
528 ///
529 /// ```
530 /// use static_iref::iri;
531 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference};
532 /// use locspan::Meta;
533 ///
534 /// # #[async_std::main]
535 /// # async fn main() {
536 /// let iri = iri!("https://example.com/sample.jsonld").to_owned();
537 /// let input1 = RemoteDocumentReference::iri(iri.clone());
538 /// let input2 = RemoteDocumentReference::iri(iri);
539 ///
540 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
541 /// // the local `example` directory. No HTTP query.
542 /// let mut loader = json_ld::FsLoader::default();
543 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
544 ///
545 /// assert!(input1.compare(
546 /// &input2,
547 /// &loader
548 /// ).await.expect("comparison failed"));
549 /// # }
550 /// ```
551 #[allow(async_fn_in_trait)]
552 async fn compare<'a>(&'a self, other: &'a Self, loader: &'a impl Loader) -> CompareResult
553 where
554 (): VocabularyMut<Iri = Iri>,
555 Iri: Clone + Eq + Hash,
556 {
557 self.compare_with(other, rdf_types::vocabulary::no_vocabulary_mut(), loader)
558 .await
559 }
560
561 /// Expand the document with the given `vocabulary` and `loader`, using
562 /// the given `options` and warning handler.
563 ///
564 /// On success, the result is an [`ExpandedDocument`].
565 ///
566 /// # Example
567 ///
568 /// ```
569 /// use static_iref::iri;
570 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
571 /// use rdf_types::vocabulary::{IriVocabularyMut, IndexVocabulary};
572 /// # #[async_std::main]
573 /// # async fn main() {
574 /// // Creates the vocabulary that will map each `rdf_types::vocabulary::Index`
575 /// // to an actual `IriBuf`.
576 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
577 ///
578 /// let iri_index = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
579 /// let input = RemoteDocumentReference::iri(iri_index);
580 ///
581 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
582 /// // the local `example` directory. No HTTP query.
583 /// let mut loader = json_ld::FsLoader::default();
584 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
585 ///
586 /// let expanded = input
587 /// .expand_full(
588 /// &mut vocabulary,
589 /// &loader,
590 /// Options::default(),
591 /// warning::PrintWith
592 /// )
593 /// .await
594 /// .expect("expansion failed");
595 /// # }
596 /// ```
597 #[allow(async_fn_in_trait)]
598 async fn expand_full<N>(
599 &self,
600 vocabulary: &mut N,
601 loader: &impl Loader,
602 options: Options<Iri>,
603 warnings: impl context_processing::WarningHandler<N> + expansion::WarningHandler<N>,
604 ) -> ExpandResult<Iri, N::BlankId>
605 where
606 N: VocabularyMut<Iri = Iri>,
607 Iri: Clone + Eq + Hash,
608 N::BlankId: Clone + Eq + Hash;
609
610 /// Expand the document with the given `vocabulary` and `loader`, using
611 /// the given `options`.
612 ///
613 /// Warnings are ignored.
614 /// On success, the result is an [`ExpandedDocument`].
615 ///
616 /// # Example
617 ///
618 /// ```
619 /// use static_iref::iri;
620 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
621 /// use rdf_types::vocabulary::{IriVocabularyMut, IndexVocabulary};
622 /// # #[async_std::main]
623 /// # async fn main() {
624 /// // Creates the vocabulary that will map each `rdf_types::vocabulary::Index`
625 /// // to an actual `IriBuf`.
626 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
627 ///
628 /// let iri_index = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
629 /// let input = RemoteDocumentReference::iri(iri_index);
630 ///
631 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
632 /// // the local `example` directory. No HTTP query.
633 /// let mut loader = json_ld::FsLoader::default();
634 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
635 ///
636 /// let expanded = input
637 /// .expand_with_using(
638 /// &mut vocabulary,
639 /// &loader,
640 /// Options::default()
641 /// )
642 /// .await
643 /// .expect("expansion failed");
644 /// # }
645 /// ```
646 #[allow(async_fn_in_trait)]
647 async fn expand_with_using<'a, N>(
648 &'a self,
649 vocabulary: &'a mut N,
650 loader: &'a impl Loader,
651 options: Options<Iri>,
652 ) -> ExpandResult<Iri, N::BlankId>
653 where
654 N: VocabularyMut<Iri = Iri>,
655 Iri: Clone + Eq + Hash,
656 N::BlankId: 'a + Clone + Eq + Hash,
657 {
658 self.expand_full(vocabulary, loader, options, ()).await
659 }
660
661 /// Expand the document with the given `vocabulary` and `loader`.
662 ///
663 /// Default options are used.
664 /// Warnings are ignored.
665 /// On success, the result is an [`ExpandedDocument`].
666 ///
667 /// # Example
668 ///
669 /// ```
670 /// use static_iref::iri;
671 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
672 /// use rdf_types::vocabulary::{IriVocabularyMut, IndexVocabulary};
673 /// # #[async_std::main]
674 /// # async fn main() {
675 /// // Creates the vocabulary that will map each `rdf_types::vocabulary::Index`
676 /// // to an actual `IriBuf`.
677 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
678 ///
679 /// let iri_index = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
680 /// let input = RemoteDocumentReference::iri(iri_index);
681 ///
682 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
683 /// // the local `example` directory. No HTTP query.
684 /// let mut loader = json_ld::FsLoader::default();
685 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
686 ///
687 /// let expanded = input
688 /// .expand_with(
689 /// &mut vocabulary,
690 /// &loader
691 /// )
692 /// .await
693 /// .expect("expansion failed");
694 /// # }
695 /// ```
696 #[allow(async_fn_in_trait)]
697 async fn expand_with<'a, N>(
698 &'a self,
699 vocabulary: &'a mut N,
700 loader: &'a impl Loader,
701 ) -> ExpandResult<Iri, N::BlankId>
702 where
703 N: VocabularyMut<Iri = Iri>,
704 Iri: Clone + Eq + Hash,
705 N::BlankId: 'a + Clone + Eq + Hash,
706 {
707 self.expand_with_using(vocabulary, loader, Options::default())
708 .await
709 }
710
711 /// Expand the document with the given `loader` using the given `options`.
712 ///
713 /// Warnings are ignored.
714 /// On success, the result is an [`ExpandedDocument`].
715 ///
716 /// # Example
717 ///
718 /// ```
719 /// use static_iref::iri;
720 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
721 ///
722 /// # #[async_std::main]
723 /// # async fn main() {
724 /// let iri = iri!("https://example.com/sample.jsonld").to_owned();
725 /// let input = RemoteDocumentReference::iri(iri);
726 ///
727 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
728 /// // the local `example` directory. No HTTP query.
729 /// let mut loader = json_ld::FsLoader::default();
730 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
731 ///
732 /// let expanded = input
733 /// .expand_using(
734 /// &loader,
735 /// Options::default()
736 /// )
737 /// .await
738 /// .expect("expansion failed");
739 /// # }
740 /// ```
741 #[allow(async_fn_in_trait)]
742 async fn expand_using<'a>(
743 &'a self,
744 loader: &'a impl Loader,
745 options: Options<Iri>,
746 ) -> ExpandResult<Iri, BlankIdBuf>
747 where
748 (): VocabularyMut<Iri = Iri>,
749 Iri: Clone + Eq + Hash,
750 {
751 self.expand_with_using(vocabulary::no_vocabulary_mut(), loader, options)
752 .await
753 }
754
755 /// Expand the document with the given `loader`.
756 ///
757 /// Default options are used.
758 /// Warnings are ignored.
759 /// On success, the result is an [`ExpandedDocument`].
760 ///
761 /// # Example
762 ///
763 /// ```
764 /// use static_iref::iri;
765 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
766 ///
767 /// # #[async_std::main]
768 /// # async fn main() {
769 /// let iri = iri!("https://example.com/sample.jsonld").to_owned();
770 /// let input = RemoteDocumentReference::iri(iri);
771 ///
772 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
773 /// // the local `example` directory. No HTTP query.
774 /// let mut loader = json_ld::FsLoader::default();
775 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
776 ///
777 /// let expanded = input
778 /// .expand(&loader)
779 /// .await
780 /// .expect("expansion failed");
781 /// # }
782 /// ```
783 #[allow(async_fn_in_trait)]
784 async fn expand<'a>(&'a self, loader: &'a impl Loader) -> ExpandResult<Iri, BlankIdBuf>
785 where
786 (): VocabularyMut<Iri = Iri>,
787 Iri: Clone + Eq + Hash,
788 {
789 self.expand_with(vocabulary::no_vocabulary_mut(), loader)
790 .await
791 }
792
793 #[allow(async_fn_in_trait)]
794 async fn into_document_full<'a, N>(
795 self,
796 vocabulary: &'a mut N,
797 loader: &'a impl Loader,
798 options: Options<Iri>,
799 warnings: impl 'a + context_processing::WarningHandler<N> + expansion::WarningHandler<N>,
800 ) -> IntoDocumentResult<Iri, N::BlankId>
801 where
802 N: VocabularyMut<Iri = Iri>,
803 Iri: 'a + Clone + Eq + Hash,
804 N::BlankId: 'a + Clone + Eq + Hash;
805
806 #[allow(async_fn_in_trait)]
807 async fn into_document_with_using<'a, N>(
808 self,
809 vocabulary: &'a mut N,
810 loader: &'a impl Loader,
811 options: Options<Iri>,
812 ) -> IntoDocumentResult<Iri, N::BlankId>
813 where
814 N: VocabularyMut<Iri = Iri>,
815 Iri: 'a + Clone + Eq + Hash,
816 N::BlankId: 'a + Clone + Eq + Hash,
817 {
818 self.into_document_full(vocabulary, loader, options, ())
819 .await
820 }
821
822 #[allow(async_fn_in_trait)]
823 async fn into_document_with<'a, N>(
824 self,
825 vocabulary: &'a mut N,
826 loader: &'a impl Loader,
827 ) -> IntoDocumentResult<Iri, N::BlankId>
828 where
829 N: VocabularyMut<Iri = Iri>,
830 Iri: 'a + Clone + Eq + Hash,
831 N::BlankId: 'a + Clone + Eq + Hash,
832 {
833 self.into_document_with_using(vocabulary, loader, Options::default())
834 .await
835 }
836
837 #[allow(async_fn_in_trait)]
838 async fn into_document<'a>(self, loader: &'a impl Loader) -> IntoDocumentResult<Iri, BlankIdBuf>
839 where
840 (): VocabularyMut<Iri = Iri>,
841 Iri: 'a + Clone + Eq + Hash,
842 {
843 self.into_document_with(vocabulary::no_vocabulary_mut(), loader)
844 .await
845 }
846
847 /// Compact the document relative to `context` with the given `vocabulary`
848 /// and `loader`, using the given `options` and warning handler.
849 ///
850 /// On success, the result is an [`syntax::Value`] wrapped inside a
851 /// [`Meta`].
852 ///
853 /// # Example
854 ///
855 /// ```
856 /// use static_iref::iri;
857 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, RemoteContextReference, warning};
858 /// use rdf_types::vocabulary::{IriVocabularyMut, IndexVocabulary};
859 /// # #[async_std::main]
860 /// # async fn main() {
861 /// // Creates the vocabulary that will map each `rdf_types::vocabulary::Index`
862 /// // to an actual `IriBuf`.
863 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
864 ///
865 /// let iri_index = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
866 /// let input = RemoteDocumentReference::iri(iri_index);
867 ///
868 /// let context_iri_index = vocabulary.insert(iri!("https://example.com/context.jsonld"));
869 /// let context = RemoteContextReference::iri(context_iri_index);
870 ///
871 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
872 /// // the local `example` directory. No HTTP query.
873 /// let mut loader = json_ld::FsLoader::default();
874 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
875 ///
876 /// let compact = input
877 /// .compact_full(
878 /// &mut vocabulary,
879 /// context,
880 /// &loader,
881 /// Options::default(),
882 /// warning::PrintWith
883 /// )
884 /// .await
885 /// .expect("compaction failed");
886 /// # }
887 /// ```
888 #[allow(async_fn_in_trait)]
889 async fn compact_full<'a, N>(
890 &'a self,
891 vocabulary: &'a mut N,
892 context: RemoteContextReference<Iri>,
893 loader: &'a impl Loader,
894 options: Options<Iri>,
895 warnings: impl 'a + context_processing::WarningHandler<N> + expansion::WarningHandler<N>,
896 ) -> CompactResult
897 where
898 N: VocabularyMut<Iri = Iri>,
899 Iri: Clone + Eq + Hash,
900 N::BlankId: 'a + Clone + Eq + Hash;
901
902 /// Compact the document relative to `context` with the given `vocabulary`
903 /// and `loader`, using the given `options`.
904 ///
905 /// Warnings are ignored.
906 /// On success, the result is an [`syntax::Value`] wrapped inside a
907 /// [`Meta`].
908 ///
909 /// # Example
910 ///
911 /// ```
912 /// use static_iref::iri;
913 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, RemoteContextReference, warning};
914 /// use rdf_types::vocabulary::{IriVocabularyMut, IndexVocabulary};
915 /// # #[async_std::main]
916 /// # async fn main() {
917 /// // Creates the vocabulary that will map each `rdf_types::vocabulary::Index`
918 /// // to an actual `IriBuf`.
919 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
920 ///
921 /// let iri_index = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
922 /// let input = RemoteDocumentReference::iri(iri_index);
923 ///
924 /// let context_iri_index = vocabulary.insert(iri!("https://example.com/context.jsonld"));
925 /// let context = RemoteContextReference::iri(context_iri_index);
926 ///
927 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
928 /// // the local `example` directory. No HTTP query.
929 /// let mut loader = json_ld::FsLoader::default();
930 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
931 ///
932 /// let compact = input
933 /// .compact_with_using(
934 /// &mut vocabulary,
935 /// context,
936 /// &loader,
937 /// Options::default()
938 /// )
939 /// .await
940 /// .expect("compaction failed");
941 /// # }
942 /// ```
943 #[allow(async_fn_in_trait)]
944 async fn compact_with_using<'a, N>(
945 &'a self,
946 vocabulary: &'a mut N,
947 context: RemoteContextReference<Iri>,
948 loader: &'a impl Loader,
949 options: Options<Iri>,
950 ) -> CompactResult
951 where
952 N: VocabularyMut<Iri = Iri>,
953 Iri: Clone + Eq + Hash,
954 N::BlankId: 'a + Clone + Eq + Hash,
955 {
956 self.compact_full(vocabulary, context, loader, options, ())
957 .await
958 }
959
960 /// Compact the document relative to `context` with the given `vocabulary`
961 /// and `loader`.
962 ///
963 /// Default options are used.
964 /// Warnings are ignored.
965 /// On success, the result is an [`syntax::Value`] wrapped inside a
966 /// [`Meta`].
967 ///
968 /// # Example
969 ///
970 /// ```
971 /// use static_iref::iri;
972 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, RemoteContextReference, warning};
973 /// use rdf_types::vocabulary::{IriVocabularyMut, IndexVocabulary};
974 /// # #[async_std::main]
975 /// # async fn main() {
976 /// // Creates the vocabulary that will map each `rdf_types::vocabulary::Index`
977 /// // to an actual `IriBuf`.
978 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
979 ///
980 /// let iri_index = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
981 /// let input = RemoteDocumentReference::iri(iri_index);
982 ///
983 /// let context_iri_index = vocabulary.insert(iri!("https://example.com/context.jsonld"));
984 /// let context = RemoteContextReference::iri(context_iri_index);
985 ///
986 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
987 /// // the local `example` directory. No HTTP query.
988 /// let mut loader = json_ld::FsLoader::default();
989 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
990 ///
991 /// let compact = input
992 /// .compact_with(
993 /// &mut vocabulary,
994 /// context,
995 /// &loader
996 /// )
997 /// .await
998 /// .expect("compaction failed");
999 /// # }
1000 /// ```
1001 #[allow(async_fn_in_trait)]
1002 async fn compact_with<'a, N>(
1003 &'a self,
1004 vocabulary: &'a mut N,
1005 context: RemoteContextReference<Iri>,
1006 loader: &'a impl Loader,
1007 ) -> CompactResult
1008 where
1009 N: VocabularyMut<Iri = Iri>,
1010 Iri: Clone + Eq + Hash,
1011 N::BlankId: 'a + Clone + Eq + Hash,
1012 {
1013 self.compact_with_using(vocabulary, context, loader, Options::default())
1014 .await
1015 }
1016
1017 /// Compact the document relative to `context` with the given `loader`,
1018 /// using the given `options`.
1019 ///
1020 /// Warnings are ignored.
1021 /// On success, the result is an [`syntax::Value`] wrapped inside a
1022 /// [`Meta`].
1023 ///
1024 /// # Example
1025 ///
1026 /// ```
1027 /// use static_iref::iri;
1028 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, RemoteContextReference, warning};
1029 ///
1030 /// # #[async_std::main]
1031 /// # async fn main() {
1032 /// let iri = iri!("https://example.com/sample.jsonld").to_owned();
1033 /// let input = RemoteDocumentReference::iri(iri);
1034 ///
1035 /// let context_iri = iri!("https://example.com/context.jsonld").to_owned();
1036 /// let context = RemoteContextReference::iri(context_iri);
1037 ///
1038 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
1039 /// // the local `example` directory. No HTTP query.
1040 /// let mut loader = json_ld::FsLoader::default();
1041 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
1042 ///
1043 /// let compact = input
1044 /// .compact_using(
1045 /// context,
1046 /// &loader,
1047 /// Options::default()
1048 /// )
1049 /// .await
1050 /// .expect("compaction failed");
1051 /// # }
1052 /// ```
1053 #[allow(async_fn_in_trait)]
1054 async fn compact_using<'a>(
1055 &'a self,
1056 context: RemoteContextReference<Iri>,
1057 loader: &'a impl Loader,
1058 options: Options<Iri>,
1059 ) -> CompactResult
1060 where
1061 (): VocabularyMut<Iri = Iri>,
1062 Iri: Clone + Eq + Hash,
1063 {
1064 self.compact_with_using(vocabulary::no_vocabulary_mut(), context, loader, options)
1065 .await
1066 }
1067
1068 /// Compact the document relative to `context` with the given `loader`.
1069 ///
1070 /// Default options are used.
1071 /// Warnings are ignored.
1072 /// On success, the result is an [`syntax::Value`] wrapped inside a
1073 /// [`Meta`].
1074 ///
1075 /// # Example
1076 ///
1077 /// ```
1078 /// use static_iref::iri;
1079 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, RemoteContextReference, warning};
1080 ///
1081 /// # #[async_std::main]
1082 /// # async fn main() {
1083 /// let iri = iri!("https://example.com/sample.jsonld").to_owned();
1084 /// let input = RemoteDocumentReference::iri(iri);
1085 ///
1086 /// let context_iri = iri!("https://example.com/context.jsonld").to_owned();
1087 /// let context = RemoteContextReference::iri(context_iri);
1088 ///
1089 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
1090 /// // the local `example` directory. No HTTP query.
1091 /// let mut loader = json_ld::FsLoader::default();
1092 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
1093 ///
1094 /// let compact = input
1095 /// .compact(
1096 /// context,
1097 /// &loader
1098 /// )
1099 /// .await
1100 /// .expect("compaction failed");
1101 /// # }
1102 /// ```
1103 #[allow(async_fn_in_trait)]
1104 async fn compact<'a>(
1105 &'a self,
1106 context: RemoteContextReference<Iri>,
1107 loader: &'a impl Loader,
1108 ) -> CompactResult
1109 where
1110 (): VocabularyMut<Iri = Iri>,
1111 Iri: Clone + Eq + Hash,
1112 {
1113 self.compact_with(vocabulary::no_vocabulary_mut(), context, loader)
1114 .await
1115 }
1116
1117 /// Flatten the document with the given `vocabulary`, `generator`
1118 /// and `loader`, using the given `options` and warning handler.
1119 ///
1120 /// An optional `context` can be given to compact the document.
1121 ///
1122 /// Flattening requires assigning an identifier to nested anonymous nodes,
1123 /// which is why the flattening functions take an [`rdf_types::MetaGenerator`]
1124 /// as parameter. This generator is in charge of creating new fresh identifiers
1125 /// (with their metadata). The most common generator is
1126 /// [`rdf_types::generator::Blank`] that creates blank node identifiers.
1127 ///
1128 /// On success, the result is a
1129 /// [`FlattenedDocument`](crate::FlattenedDocument), which is a list of
1130 /// indexed nodes.
1131 ///
1132 /// # Example
1133 ///
1134 /// ```
1135 /// use static_iref::iri;
1136 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
1137 /// use rdf_types::vocabulary::{IriVocabularyMut, IndexVocabulary};
1138 ///
1139 /// # #[async_std::main]
1140 /// # async fn main() {
1141 /// // Creates the vocabulary that will map each `rdf_types::vocabulary::Index`
1142 /// // to an actual `IriBuf`.
1143 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
1144 ///
1145 /// let iri_index = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
1146 /// let input = RemoteDocumentReference::iri(iri_index);
1147 ///
1148 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
1149 /// // the local `example` directory. No HTTP query.
1150 /// let mut loader = json_ld::FsLoader::default();
1151 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
1152 ///
1153 /// let mut generator = rdf_types::generator::Blank::new();
1154 ///
1155 /// let nodes = input
1156 /// .flatten_full(
1157 /// &mut vocabulary,
1158 /// &mut generator,
1159 /// None,
1160 /// &loader,
1161 /// Options::default(),
1162 /// warning::PrintWith
1163 /// )
1164 /// .await
1165 /// .expect("flattening failed");
1166 /// # }
1167 /// ```
1168 #[allow(async_fn_in_trait)]
1169 async fn flatten_full<'a, N>(
1170 &'a self,
1171 vocabulary: &'a mut N,
1172 generator: &'a mut impl Generator<N>,
1173 context: Option<RemoteContextReference<Iri>>,
1174 loader: &'a impl Loader,
1175 options: Options<Iri>,
1176 warnings: impl 'a + context_processing::WarningHandler<N> + expansion::WarningHandler<N>,
1177 ) -> FlattenResult<Iri, N::BlankId>
1178 where
1179 N: VocabularyMut<Iri = Iri>,
1180 Iri: Clone + Eq + Hash,
1181 N::BlankId: 'a + Clone + Eq + Hash;
1182
1183 /// Flatten the document with the given `vocabulary`, `generator`
1184 /// and `loader`, using the given `options`.
1185 ///
1186 /// Flattening requires assigning an identifier to nested anonymous nodes,
1187 /// which is why the flattening functions take an [`rdf_types::MetaGenerator`]
1188 /// as parameter. This generator is in charge of creating new fresh identifiers
1189 /// (with their metadata). The most common generator is
1190 /// [`rdf_types::generator::Blank`] that creates blank node identifiers.
1191 ///
1192 /// Warnings are ignored.
1193 /// On success, the result is a
1194 /// [`FlattenedDocument`](crate::FlattenedDocument), which is a list of
1195 /// indexed nodes.
1196 ///
1197 /// # Example
1198 ///
1199 /// ```
1200 /// use static_iref::iri;
1201 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
1202 /// use rdf_types::vocabulary::{IriVocabularyMut, IndexVocabulary};
1203 ///
1204 /// # #[async_std::main]
1205 /// # async fn main() {
1206 /// // Creates the vocabulary that will map each `rdf_types::vocabulary::Index`
1207 /// // to an actual `IriBuf`.
1208 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
1209 ///
1210 /// let iri_index = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
1211 /// let input = RemoteDocumentReference::iri(iri_index);
1212 ///
1213 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
1214 /// // the local `example` directory. No HTTP query.
1215 /// let mut loader = json_ld::FsLoader::default();
1216 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
1217 ///
1218 /// let mut generator = rdf_types::generator::Blank::new();
1219 ///
1220 /// let nodes = input
1221 /// .flatten_with_using(
1222 /// &mut vocabulary,
1223 /// &mut generator,
1224 /// &loader,
1225 /// Options::default()
1226 /// )
1227 /// .await
1228 /// .expect("flattening failed");
1229 /// # }
1230 /// ```
1231 #[allow(async_fn_in_trait)]
1232 async fn flatten_with_using<'a, N>(
1233 &'a self,
1234 vocabulary: &'a mut N,
1235 generator: &'a mut impl Generator<N>,
1236 loader: &'a impl Loader,
1237 options: Options<Iri>,
1238 ) -> FlattenResult<Iri, N::BlankId>
1239 where
1240 N: VocabularyMut<Iri = Iri>,
1241 Iri: Clone + Eq + Hash,
1242 N::BlankId: 'a + Clone + Eq + Hash,
1243 {
1244 self.flatten_full(vocabulary, generator, None, loader, options, ())
1245 .await
1246 }
1247
1248 /// Flatten the document with the given `vocabulary`, `generator`
1249 /// and `loader`.
1250 ///
1251 /// Flattening requires assigning an identifier to nested anonymous nodes,
1252 /// which is why the flattening functions take an [`rdf_types::MetaGenerator`]
1253 /// as parameter. This generator is in charge of creating new fresh identifiers
1254 /// (with their metadata). The most common generator is
1255 /// [`rdf_types::generator::Blank`] that creates blank node identifiers.
1256 ///
1257 /// Default options are used.
1258 /// Warnings are ignored.
1259 /// On success, the result is a
1260 /// [`FlattenedDocument`](crate::FlattenedDocument), which is a list of
1261 /// indexed nodes.
1262 ///
1263 /// # Example
1264 ///
1265 /// ```
1266 /// use static_iref::iri;
1267 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
1268 /// use rdf_types::vocabulary::{IriVocabularyMut, IndexVocabulary};
1269 ///
1270 /// # #[async_std::main]
1271 /// # async fn main() {
1272 /// // Creates the vocabulary that will map each `rdf_types::vocabulary::Index`
1273 /// // to an actual `IriBuf`.
1274 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
1275 ///
1276 /// let iri_index = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
1277 /// let input = RemoteDocumentReference::iri(iri_index);
1278 ///
1279 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
1280 /// // the local `example` directory. No HTTP query.
1281 /// let mut loader = json_ld::FsLoader::default();
1282 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
1283 ///
1284 /// let mut generator = rdf_types::generator::Blank::new();
1285 ///
1286 /// let nodes = input
1287 /// .flatten_with(
1288 /// &mut vocabulary,
1289 /// &mut generator,
1290 /// &loader
1291 /// )
1292 /// .await
1293 /// .expect("flattening failed");
1294 /// # }
1295 /// ```
1296 #[allow(async_fn_in_trait)]
1297 async fn flatten_with<'a, N>(
1298 &'a self,
1299 vocabulary: &'a mut N,
1300 generator: &'a mut impl Generator<N>,
1301 loader: &'a impl Loader,
1302 ) -> FlattenResult<Iri, N::BlankId>
1303 where
1304 N: VocabularyMut<Iri = Iri>,
1305 Iri: Clone + Eq + Hash,
1306 N::BlankId: 'a + Clone + Eq + Hash,
1307 {
1308 self.flatten_with_using(vocabulary, generator, loader, Options::default())
1309 .await
1310 }
1311
1312 /// Flatten the document with the given `generator`, `loader` and using the
1313 /// given `options`.
1314 ///
1315 /// Flattening requires assigning an identifier to nested anonymous nodes,
1316 /// which is why the flattening functions take an [`rdf_types::MetaGenerator`]
1317 /// as parameter. This generator is in charge of creating new fresh identifiers
1318 /// (with their metadata). The most common generator is
1319 /// [`rdf_types::generator::Blank`] that creates blank node identifiers.
1320 ///
1321 /// Warnings are ignored.
1322 /// On success, the result is a
1323 /// [`FlattenedDocument`](crate::FlattenedDocument), which is a list of
1324 /// indexed nodes.
1325 ///
1326 /// # Example
1327 ///
1328 /// ```
1329 /// use static_iref::iri;
1330 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
1331 ///
1332 /// # #[async_std::main]
1333 /// # async fn main() {
1334 /// let iri = iri!("https://example.com/sample.jsonld").to_owned();
1335 /// let input = RemoteDocumentReference::iri(iri);
1336 ///
1337 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
1338 /// // the local `example` directory. No HTTP query.
1339 /// let mut loader = json_ld::FsLoader::default();
1340 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
1341 ///
1342 /// let mut generator = rdf_types::generator::Blank::new();
1343 ///
1344 /// let nodes = input
1345 /// .flatten_using(
1346 /// &mut generator,
1347 /// &loader,
1348 /// Options::default()
1349 /// )
1350 /// .await
1351 /// .expect("flattening failed");
1352 /// # }
1353 /// ```
1354 #[allow(async_fn_in_trait)]
1355 async fn flatten_using<'a>(
1356 &'a self,
1357 generator: &'a mut impl Generator,
1358 loader: &'a impl Loader,
1359 options: Options<Iri>,
1360 ) -> FlattenResult<Iri, BlankIdBuf>
1361 where
1362 (): VocabularyMut<Iri = Iri>,
1363 Iri: Clone + Eq + Hash,
1364 {
1365 self.flatten_with_using(vocabulary::no_vocabulary_mut(), generator, loader, options)
1366 .await
1367 }
1368
1369 /// Flatten the document with the given `generator` and `loader`.
1370 ///
1371 /// Flattening requires assigning an identifier to nested anonymous nodes,
1372 /// which is why the flattening functions take an [`rdf_types::MetaGenerator`]
1373 /// as parameter. This generator is in charge of creating new fresh identifiers
1374 /// (with their metadata). The most common generator is
1375 /// [`rdf_types::generator::Blank`] that creates blank node identifiers.
1376 ///
1377 /// Default options are used.
1378 /// Warnings are ignored.
1379 /// On success, the result is a
1380 /// [`FlattenedDocument`](crate::FlattenedDocument), which is a list of
1381 /// indexed nodes.
1382 ///
1383 /// # Example
1384 ///
1385 /// ```
1386 /// use static_iref::iri;
1387 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
1388 ///
1389 /// # #[async_std::main]
1390 /// # async fn main() {
1391 /// let iri = iri!("https://example.com/sample.jsonld").to_owned();
1392 /// let input = RemoteDocumentReference::iri(iri);
1393 ///
1394 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
1395 /// // the local `example` directory. No HTTP query.
1396 /// let mut loader = json_ld::FsLoader::default();
1397 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
1398 ///
1399 /// let mut generator = rdf_types::generator::Blank::new();
1400 ///
1401 /// let nodes = input
1402 /// .flatten(
1403 /// &mut generator,
1404 /// &loader
1405 /// )
1406 /// .await
1407 /// .expect("flattening failed");
1408 /// # }
1409 /// ```
1410 #[allow(async_fn_in_trait)]
1411 async fn flatten<'a>(
1412 &'a self,
1413 generator: &'a mut impl Generator,
1414 loader: &'a impl Loader,
1415 ) -> FlattenResult<Iri, BlankIdBuf>
1416 where
1417 (): VocabularyMut<Iri = Iri>,
1418 Iri: Clone + Eq + Hash,
1419 {
1420 self.flatten_with(vocabulary::no_vocabulary_mut(), generator, loader)
1421 .await
1422 }
1423
1424 /// Serializes the document into an RDF dataset with a custom vocabulary
1425 /// using the given `options` and warnings handler.
1426 ///
1427 /// Expands the document and returns a [`ToRdf`] instance from which an
1428 /// iterator over the RDF quads defined by the document can be accessed
1429 /// using the [`ToRdf::quads`] method.
1430 ///
1431 /// The quads will have type [`rdf::Quads`] which borrows the subject,
1432 /// predicate and graph values from the documents if possible using [`Cow`].
1433 /// If you prefer to have quads owning the values directly you can use the
1434 /// [`ToRdf::cloned_quads`] method or call the [`rdf::Quads::cloned`]
1435 /// method method form the value returned by [`ToRdf::quads`].
1436 ///
1437 /// [`rdf::Quads`]: json_ld_core::rdf::Quads
1438 /// [`rdf::Quads::cloned`]: json_ld_core::rdf::Quads::cloned
1439 /// [`Cow`]: std::borrow::Cow
1440 ///
1441 /// # Example
1442 ///
1443 /// ```
1444 /// use static_iref::iri;
1445 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
1446 /// use rdf_types::{Quad, vocabulary::{IriVocabularyMut, IndexVocabulary}};
1447 ///
1448 /// # #[async_std::main]
1449 /// # async fn main() {
1450 /// // Creates the vocabulary that will map each `rdf_types::vocabulary::Index`
1451 /// // to an actual `IriBuf`.
1452 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
1453 ///
1454 /// let iri_index = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
1455 /// let input = RemoteDocumentReference::iri(iri_index);
1456 ///
1457 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
1458 /// // the local `example` directory. No HTTP query.
1459 /// let mut loader = json_ld::FsLoader::default();
1460 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
1461 ///
1462 /// let mut generator = rdf_types::generator::Blank::new();
1463 ///
1464 /// let mut rdf = input
1465 /// .to_rdf_full(
1466 /// &mut vocabulary,
1467 /// &mut generator,
1468 /// &loader,
1469 /// Options::default(),
1470 /// warning::PrintWith
1471 /// )
1472 /// .await
1473 /// .expect("flattening failed");
1474 ///
1475 /// for Quad(_s, _p, _o, _g) in rdf.quads() {
1476 /// // ...
1477 /// }
1478 /// # }
1479 /// ```
1480 #[allow(async_fn_in_trait)]
1481 async fn to_rdf_full<N, G>(
1482 &self,
1483 mut vocabulary: N,
1484 generator: G,
1485 loader: &impl Loader,
1486 options: Options<Iri>,
1487 warnings: impl context_processing::WarningHandler<N> + expansion::WarningHandler<N>,
1488 ) -> ToRdfResult<N, G>
1489 where
1490 N: VocabularyMut<Iri = Iri>,
1491 Iri: Clone + Eq + Hash,
1492 N::BlankId: Clone + Eq + Hash,
1493 G: Generator<N>,
1494 {
1495 let rdf_direction = options.rdf_direction;
1496 let produce_generalized_rdf = options.produce_generalized_rdf;
1497 let expanded_input = self
1498 .expand_full(&mut vocabulary, loader, options.unordered(), warnings)
1499 .await
1500 .map_err(ToRdfError::Expand)?;
1501 Ok(ToRdf::new(
1502 vocabulary,
1503 generator,
1504 expanded_input,
1505 rdf_direction,
1506 produce_generalized_rdf,
1507 ))
1508 }
1509
1510 /// Serializes the document into an RDF dataset with a custom vocabulary
1511 /// using the given `options`.
1512 ///
1513 /// Expands the document and returns a [`ToRdf`] instance from which an
1514 /// iterator over the RDF quads defined by the document can be accessed
1515 /// using the [`ToRdf::quads`] method.
1516 ///
1517 /// The quads will have type [`rdf::Quads`] which borrows the subject,
1518 /// predicate and graph values from the documents if possible using [`Cow`].
1519 /// If you prefer to have quads owning the values directly you can use the
1520 /// [`ToRdf::cloned_quads`] method or call the [`rdf::Quads::cloned`]
1521 /// method method form the value returned by [`ToRdf::quads`].
1522 ///
1523 /// [`rdf::Quads`]: json_ld_core::rdf::Quads
1524 /// [`rdf::Quads::cloned`]: json_ld_core::rdf::Quads::cloned
1525 /// [`Cow`]: std::borrow::Cow
1526 ///
1527 /// # Example
1528 ///
1529 /// ```
1530 /// use static_iref::iri;
1531 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
1532 /// use rdf_types::{Quad, vocabulary::{IriVocabularyMut, IndexVocabulary}};
1533 ///
1534 /// # #[async_std::main]
1535 /// # async fn main() {
1536 /// // Creates the vocabulary that will map each `rdf_types::vocabulary::Index`
1537 /// // to an actual `IriBuf`.
1538 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
1539 ///
1540 /// let iri_index = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
1541 /// let input = RemoteDocumentReference::iri(iri_index);
1542 ///
1543 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
1544 /// // the local `example` directory. No HTTP query.
1545 /// let mut loader = json_ld::FsLoader::default();
1546 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
1547 ///
1548 /// let mut generator = rdf_types::generator::Blank::new();
1549 ///
1550 /// let mut rdf = input
1551 /// .to_rdf_with_using(
1552 /// &mut vocabulary,
1553 /// &mut generator,
1554 /// &loader,
1555 /// Options::default()
1556 /// )
1557 /// .await
1558 /// .expect("flattening failed");
1559 ///
1560 /// for Quad(_s, _p, _o, _g) in rdf.quads() {
1561 /// // ...
1562 /// }
1563 /// # }
1564 /// ```
1565 #[allow(async_fn_in_trait)]
1566 async fn to_rdf_with_using<N, G>(
1567 &self,
1568 vocabulary: N,
1569 generator: G,
1570 loader: &impl Loader,
1571 options: Options<Iri>,
1572 ) -> ToRdfResult<N, G>
1573 where
1574 N: VocabularyMut<Iri = Iri>,
1575 Iri: Clone + Eq + Hash,
1576 N::BlankId: Clone + Eq + Hash,
1577 G: Generator<N>,
1578 {
1579 self.to_rdf_full(vocabulary, generator, loader, options, ())
1580 .await
1581 }
1582
1583 /// Serializes the document into an RDF dataset with a custom vocabulary.
1584 ///
1585 /// Default options are used.
1586 ///
1587 /// Expands the document and returns a [`ToRdf`] instance from which an
1588 /// iterator over the RDF quads defined by the document can be accessed
1589 /// using the [`ToRdf::quads`] method.
1590 ///
1591 /// The quads will have type [`rdf::Quads`] which borrows the subject,
1592 /// predicate and graph values from the documents if possible using [`Cow`].
1593 /// If you prefer to have quads owning the values directly you can use the
1594 /// [`ToRdf::cloned_quads`] method or call the [`rdf::Quads::cloned`]
1595 /// method method form the value returned by [`ToRdf::quads`].
1596 ///
1597 /// [`rdf::Quads`]: json_ld_core::rdf::Quads
1598 /// [`rdf::Quads::cloned`]: json_ld_core::rdf::Quads::cloned
1599 /// [`Cow`]: std::borrow::Cow
1600 ///
1601 /// # Example
1602 ///
1603 /// ```
1604 /// use static_iref::iri;
1605 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
1606 /// use rdf_types::{Quad, vocabulary::{IriVocabularyMut, IndexVocabulary}};
1607 ///
1608 /// # #[async_std::main]
1609 /// # async fn main() {
1610 /// // Creates the vocabulary that will map each `rdf_types::vocabulary::Index`
1611 /// // to an actual `IriBuf`.
1612 /// let mut vocabulary: IndexVocabulary = IndexVocabulary::new();
1613 ///
1614 /// let iri_index = vocabulary.insert(iri!("https://example.com/sample.jsonld"));
1615 /// let input = RemoteDocumentReference::iri(iri_index);
1616 ///
1617 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
1618 /// // the local `example` directory. No HTTP query.
1619 /// let mut loader = json_ld::FsLoader::default();
1620 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
1621 ///
1622 /// let mut generator = rdf_types::generator::Blank::new();
1623 ///
1624 /// let mut rdf = input
1625 /// .to_rdf_with(
1626 /// &mut vocabulary,
1627 /// &mut generator,
1628 /// &loader
1629 /// )
1630 /// .await
1631 /// .expect("flattening failed");
1632 ///
1633 /// for Quad(_s, _p, _o, _g) in rdf.quads() {
1634 /// // ...
1635 /// }
1636 /// # }
1637 /// ```
1638 #[allow(async_fn_in_trait)]
1639 async fn to_rdf_with<N, G>(
1640 &self,
1641 vocabulary: N,
1642 generator: G,
1643 loader: &impl Loader,
1644 ) -> ToRdfResult<N, G>
1645 where
1646 N: VocabularyMut<Iri = Iri>,
1647 Iri: Clone + Eq + Hash,
1648 N::BlankId: Clone + Eq + Hash,
1649 G: Generator<N>,
1650 {
1651 self.to_rdf_full(vocabulary, generator, loader, Options::default(), ())
1652 .await
1653 }
1654
1655 /// Serializes the document into an RDF dataset using the given `options`.
1656 ///
1657 /// Expands the document and returns a [`ToRdf`] instance from which an
1658 /// iterator over the RDF quads defined by the document can be accessed
1659 /// using the [`ToRdf::quads`] method.
1660 ///
1661 /// The quads will have type [`rdf::Quads`] which borrows the subject,
1662 /// predicate and graph values from the documents if possible using [`Cow`].
1663 /// If you prefer to have quads owning the values directly you can use the
1664 /// [`ToRdf::cloned_quads`] method or call the [`rdf::Quads::cloned`]
1665 /// method method form the value returned by [`ToRdf::quads`].
1666 ///
1667 /// [`rdf::Quads`]: json_ld_core::rdf::Quads
1668 /// [`rdf::Quads::cloned`]: json_ld_core::rdf::Quads::cloned
1669 /// [`Cow`]: std::borrow::Cow
1670 ///
1671 /// # Example
1672 ///
1673 /// ```
1674 /// use static_iref::iri;
1675 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
1676 /// use rdf_types::Quad;
1677 /// use locspan::{Location, Span};
1678 ///
1679 /// # #[async_std::main]
1680 /// # async fn main() {
1681 /// let iri_index = iri!("https://example.com/sample.jsonld").to_owned();
1682 /// let input = RemoteDocumentReference::iri(iri_index);
1683 ///
1684 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
1685 /// // the local `example` directory. No HTTP query.
1686 /// let mut loader = json_ld::FsLoader::default();
1687 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
1688 ///
1689 /// let mut generator = rdf_types::generator::Blank::new();
1690 ///
1691 /// let mut rdf = input
1692 /// .to_rdf_using(
1693 /// &mut generator,
1694 /// &loader,
1695 /// Options::default()
1696 /// )
1697 /// .await
1698 /// .expect("flattening failed");
1699 ///
1700 /// for Quad(s, p, o, g) in rdf.quads() {
1701 /// println!("subject: {}", s);
1702 /// println!("predicate: {}", p);
1703 /// println!("object: {}", o);
1704 ///
1705 /// if let Some(g) = g {
1706 /// println!("graph: {}", g);
1707 /// }
1708 /// }
1709 /// # }
1710 /// ```
1711 #[allow(async_fn_in_trait)]
1712 async fn to_rdf_using<G>(
1713 &self,
1714 generator: G,
1715 loader: &impl Loader,
1716 options: Options<Iri>,
1717 ) -> ToRdfResult<(), G>
1718 where
1719 (): VocabularyMut<Iri = Iri>,
1720 Iri: Clone + Eq + Hash,
1721 G: Generator,
1722 {
1723 self.to_rdf_with_using((), generator, loader, options).await
1724 }
1725
1726 /// Serializes the document into an RDF dataset.
1727 ///
1728 /// Default options are used.
1729 ///
1730 /// Expands the document and returns a [`ToRdf`] instance from which an
1731 /// iterator over the RDF quads defined by the document can be accessed
1732 /// using the [`ToRdf::quads`] method.
1733 ///
1734 /// The quads will have type [`rdf::Quads`] which borrows the subject,
1735 /// predicate and graph values from the documents if possible using [`Cow`].
1736 /// If you prefer to have quads owning the values directly you can use the
1737 /// [`ToRdf::cloned_quads`] method or call the [`rdf::Quads::cloned`]
1738 /// method method form the value returned by [`ToRdf::quads`].
1739 ///
1740 /// [`rdf::Quads`]: json_ld_core::rdf::Quads
1741 /// [`rdf::Quads::cloned`]: json_ld_core::rdf::Quads::cloned
1742 /// [`Cow`]: std::borrow::Cow
1743 ///
1744 /// # Example
1745 ///
1746 /// ```
1747 /// use static_iref::iri;
1748 /// use json_ld::{JsonLdProcessor, Options, RemoteDocumentReference, warning};
1749 /// use rdf_types::Quad;
1750 /// use locspan::{Location, Span};
1751 ///
1752 /// # #[async_std::main]
1753 /// # async fn main() {
1754 /// let iri_index = iri!("https://example.com/sample.jsonld").to_owned();
1755 /// let input = RemoteDocumentReference::iri(iri_index);
1756 ///
1757 /// // Use `FsLoader` to redirect any URL starting with `https://example.com/` to
1758 /// // the local `example` directory. No HTTP query.
1759 /// let mut loader = json_ld::FsLoader::default();
1760 /// loader.mount(iri!("https://example.com/").to_owned(), "examples");
1761 ///
1762 /// let mut generator = rdf_types::generator::Blank::new();
1763 ///
1764 /// let mut rdf = input
1765 /// .to_rdf(
1766 /// &mut generator,
1767 /// &loader
1768 /// )
1769 /// .await
1770 /// .expect("flattening failed");
1771 ///
1772 /// for Quad(s, p, o, g) in rdf.quads() {
1773 /// println!("subject: {}", s);
1774 /// println!("predicate: {}", p);
1775 /// println!("object: {}", o);
1776 ///
1777 /// if let Some(g) = g {
1778 /// println!("graph: {}", g);
1779 /// }
1780 /// }
1781 /// # }
1782 /// ```
1783 #[allow(async_fn_in_trait)]
1784 async fn to_rdf<G>(&self, generator: G, loader: &impl Loader) -> ToRdfResult<(), G>
1785 where
1786 (): VocabularyMut<Iri = Iri>,
1787 Iri: Clone + Eq + Hash,
1788 G: Generator,
1789 {
1790 self.to_rdf_using(generator, loader, Options::default())
1791 .await
1792 }
1793}
1794
1795pub struct ToRdf<V: Vocabulary, G> {
1796 vocabulary: V,
1797 generator: G,
1798 doc: ExpandedDocument<V::Iri, V::BlankId>,
1799 rdf_direction: Option<RdfDirection>,
1800 produce_generalized_rdf: bool,
1801}
1802
1803impl<V: Vocabulary, G: rdf_types::Generator<V>> ToRdf<V, G> {
1804 fn new(
1805 mut vocabulary: V,
1806 mut generator: G,
1807 mut doc: ExpandedDocument<V::Iri, V::BlankId>,
1808 rdf_direction: Option<RdfDirection>,
1809 produce_generalized_rdf: bool,
1810 ) -> Self
1811 where
1812 V::Iri: Clone + Eq + Hash,
1813 V::BlankId: Clone + Eq + Hash,
1814 {
1815 doc.relabel_and_canonicalize_with(&mut vocabulary, &mut generator);
1816 Self {
1817 vocabulary,
1818 generator,
1819 doc,
1820 rdf_direction,
1821 produce_generalized_rdf,
1822 }
1823 }
1824
1825 pub fn quads(&mut self) -> json_ld_core::rdf::Quads<'_, V, G> {
1826 self.doc.rdf_quads_full(
1827 &mut self.vocabulary,
1828 &mut self.generator,
1829 self.rdf_direction,
1830 self.produce_generalized_rdf,
1831 )
1832 }
1833
1834 #[inline(always)]
1835 pub fn cloned_quads(&mut self) -> json_ld_core::rdf::ClonedQuads<'_, V, G> {
1836 self.quads().cloned()
1837 }
1838
1839 pub fn vocabulary(&self) -> &V {
1840 &self.vocabulary
1841 }
1842
1843 pub fn vocabulary_mut(&mut self) -> &mut V {
1844 &mut self.vocabulary
1845 }
1846
1847 pub fn into_vocabulary(self) -> V {
1848 self.vocabulary
1849 }
1850
1851 pub fn generator(&self) -> &G {
1852 &self.generator
1853 }
1854
1855 pub fn generator_mut(&mut self) -> &mut G {
1856 &mut self.generator
1857 }
1858
1859 pub fn into_generator(self) -> G {
1860 self.generator
1861 }
1862
1863 pub fn document(&self) -> &ExpandedDocument<V::Iri, V::BlankId> {
1864 &self.doc
1865 }
1866
1867 pub fn document_mut(&mut self) -> &mut ExpandedDocument<V::Iri, V::BlankId> {
1868 &mut self.doc
1869 }
1870
1871 pub fn into_document(self) -> ExpandedDocument<V::Iri, V::BlankId> {
1872 self.doc
1873 }
1874}
1875
1876async fn compact_expanded_full<'a, T, N, L>(
1877 expanded_input: &'a T,
1878 url: Option<&'a N::Iri>,
1879 vocabulary: &'a mut N,
1880 context: RemoteContextReference<N::Iri>,
1881 loader: &'a L,
1882 options: Options<N::Iri>,
1883 warnings: impl context_processing::WarningHandler<N>,
1884) -> Result<json_syntax::Value, CompactError>
1885where
1886 N: VocabularyMut,
1887 N::Iri: Clone + Eq + Hash,
1888 N::BlankId: 'a + Clone + Eq + Hash,
1889 T: Compact<N::Iri, N::BlankId>,
1890 L: Loader,
1891{
1892 let context_base = url.or(options.base.as_ref());
1893
1894 let context = context
1895 .load_context_with(vocabulary, loader)
1896 .await
1897 .map_err(CompactError::ContextLoading)?
1898 .into_document();
1899
1900 let mut active_context = context
1901 .process_full(
1902 vocabulary,
1903 &Context::new(None),
1904 loader,
1905 context_base.cloned(),
1906 options.context_processing_options(),
1907 warnings,
1908 )
1909 .await
1910 .map_err(CompactError::ContextProcessing)?;
1911
1912 match options.base.as_ref() {
1913 Some(base) => active_context.set_base_iri(Some(base.clone())),
1914 None => {
1915 if options.compact_to_relative && active_context.base_iri().is_none() {
1916 active_context.set_base_iri(url.cloned());
1917 }
1918 }
1919 }
1920
1921 expanded_input
1922 .compact_full(
1923 vocabulary,
1924 active_context.as_ref(),
1925 loader,
1926 options.compaction_options(),
1927 )
1928 .await
1929 .map_err(CompactError::Compaction)
1930}
1931
1932#[cfg(test)]
1933mod tests {
1934 use futures::Future;
1935 use json_ld_core::{NoLoader, RemoteDocument};
1936 use json_syntax::Value;
1937 use rdf_types::generator;
1938
1939 use crate::JsonLdProcessor;
1940
1941 async fn assert_send<F: Future + Send>(f: F) -> F::Output {
1942 f.await
1943 }
1944
1945 #[async_std::test]
1946 async fn to_rdf_is_send() {
1947 let generator = generator::Blank::new();
1948 let document = RemoteDocument::new(None, None, Value::Null);
1949 let f = document.to_rdf(generator, &NoLoader);
1950 let _ = assert_send(f).await;
1951 }
1952}