1use core::fmt;
23use crate::{LoadError, LoadErrorCause, LoadingResult};
4use iref::{Iri, IriBuf};
56use super::Loader;
78/// * [`ChainLoader`]: loads document from the first loader, otherwise falls back to the second one.
9///
10/// This can be useful for combining, for example,
11/// an [`FsLoader`](super::FsLoader) for loading some contexts from a local cache,
12/// and a [`ReqwestLoader`](super::ReqwestLoader) for loading any other context from the web.
13///
14/// Note that it is also possible to nest several [`ChainLoader`]s,
15/// to combine more than two loaders.
16pub struct ChainLoader<L1, L2>(L1, L2);
1718impl<L1, L2> ChainLoader<L1, L2> {
19/// Build a new chain loader
20pub fn new(l1: L1, l2: L2) -> Self {
21 ChainLoader(l1, l2)
22 }
23}
2425impl<L1, L2> Loader for ChainLoader<L1, L2>
26where
27L1: Loader,
28 L2: Loader,
29{
30async fn load(&self, url: &Iri) -> LoadingResult<IriBuf> {
31match self.0.load(url).await {
32Ok(doc) => Ok(doc),
33Err(LoadError { cause: e1, .. }) => match self.1.load(url).await {
34Ok(doc) => Ok(doc),
35Err(LoadError { target, cause: e2 }) => Err(LoadError::new(target, Error(e1, e2))),
36 },
37 }
38 }
39}
4041/// Either-or error.
42#[derive(Debug)]
43pub struct Error(pub LoadErrorCause, pub LoadErrorCause);
4445impl fmt::Display for Error {
46fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47let Error(e1, e2) = self;
48write!(f, "{e1}, then {e2}")
49 }
50}
5152impl std::error::Error for Error {}