jsonld_core/loader/dereference.rs
1//! Invoking the `LoadDocumentCallback` from inside an algorithm.
2//!
3//! The algorithms recurse once per nesting level of their input, and keep that
4//! recursion off the caller's native stack by checking, at every recursion
5//! point, that at least [`RED_ZONE`] of it is left
6//! ([`native_stack`](jsonld_syntax::native_stack)). Dereferencing a document
7//! leaves the algorithm for the embedder's [`Loader`]: an HTTP client behind a
8//! cache, say, whose native stack per poll the crate cannot bound. Polled
9//! without a check of its own, a loader runs on whatever the last recursion
10//! point left, which may be only a little more than the red zone.
11//!
12//! [`Dereference::dereference`] is therefore the one way an algorithm invokes a
13//! loader: every poll of the loader runs as a recursion point does, so it
14//! always starts with at least [`RED_ZONE`] of native stack. The workspace
15//! `clippy.toml` disallows calling [`Loader::load`] and [`Loader::load_with`]
16//! anywhere else.
17//!
18//! [`RED_ZONE`]: jsonld_syntax::native_stack::RED_ZONE
19
20use crate::loader::{Loader, LoadingResult};
21use jsonld_syntax::native_stack::Recursion;
22use rdfx::vocabulary::IriVocabularyMut;
23use std::{future::Future, hash::Hash};
24
25/// Dereferencing a document through a [`Loader`] on sufficient native stack.
26///
27/// Implemented for every loader; an algorithm calls [`Self::dereference`]
28/// where the JSON-LD 1.1 API invokes the `LoadDocumentCallback`.
29pub trait Dereference: Loader {
30 /// Loads the document behind `url`, using `vocabulary`, polling the loader
31 /// on at least [`RED_ZONE`](jsonld_syntax::native_stack::RED_ZONE) of
32 /// native stack.
33 ///
34 /// # Errors
35 ///
36 /// Returns the loader's error when the document cannot be fetched or
37 /// parsed.
38 fn dereference<V>(&self, vocabulary: &mut V, url: V::Iri) -> impl Future<Output = LoadingResult<V::Iri, Self::Error>>
39 where
40 V: IriVocabularyMut,
41 V::Iri: Clone + Eq + Hash;
42}
43
44impl<L: Loader + ?Sized> Dereference for L {
45 fn dereference<V>(&self, vocabulary: &mut V, url: V::Iri) -> impl Future<Output = LoadingResult<V::Iri, Self::Error>>
46 where
47 V: IriVocabularyMut,
48 V::Iri: Clone + Eq + Hash,
49 {
50 #[expect(clippy::disallowed_methods, reason = "the one guarded invocation of a loader every algorithm goes through")]
51 let loading = self.load_with(vocabulary, url);
52 Recursion::new(loading)
53 }
54}