sophia_jsonld/loader/
chain_loader.rs

1use std::fmt::Debug;
2
3use json_ld::future::{BoxFuture, FutureExt};
4use json_ld::Loader;
5use json_syntax::Value;
6use locspan::Location;
7
8/// * [`ChainLoader`]: loads document from the first loader, otherwise falls back to the second one.
9#[derive(Clone, Debug, Default)]
10pub struct ChainLoader<L1, L2>(L1, L2);
11
12impl<L1, L2> ChainLoader<L1, L2> {
13    /// Build a new chain loader
14    pub const fn new(l1: L1, l2: L2) -> Self {
15        Self(l1, l2)
16    }
17}
18
19impl<I, L1, L2> Loader<I, Location<I>> for ChainLoader<L1, L2>
20where
21    I: Clone + Send + Sync,
22    L1: Loader<I, Location<I>, Output = Value<Location<I>>> + Send,
23    L2: Loader<I, Location<I>, Output = Value<Location<I>>> + Send,
24    L1::Error: Debug + Send,
25    L2::Error: Debug,
26{
27    type Output = Value<Location<I>>;
28
29    type Error = ChainLoaderError<L1::Error, L2::Error>;
30
31    fn load_with<'a>(
32        &'a mut self,
33        vocabulary: &'a mut (impl Sync + Send + rdf_types::IriVocabularyMut<Iri = I>),
34        url: I,
35    ) -> BoxFuture<'a, json_ld::LoadingResult<I, Location<I>, Self::Output, Self::Error>>
36    where
37        I: 'a,
38    {
39        async {
40            match self.0.load_with(vocabulary, url.clone()).await {
41                Ok(doc) => Ok(doc),
42                Err(err1) => match self.1.load_with(vocabulary, url).await {
43                    Ok(doc) => Ok(doc),
44                    Err(err2) => Err(ChainLoaderError(err1, err2)),
45                },
46            }
47        }
48        .boxed()
49    }
50}
51
52/// Error type raised by [`ChainLoader`]
53#[derive(thiserror::Error, Debug)]
54#[error("Document not found {0}")]
55pub struct ChainLoaderError<E1, E2>(E1, E2)
56where
57    E1: Debug,
58    E2: Debug;