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}