Skip to main content

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}