json_ld/core/loader/
mod.rs1use json_syntax::JsonValue;
2use rdf_syntax::{Iri, IriBuf};
3use std::{borrow::Cow, sync::LazyLock};
4
5use crate::{JsonLdDocument, syntax::JsonLdContextDocumentValue};
6
7pub mod chain;
8pub mod fs;
9pub mod map;
10pub mod none;
11#[cfg(feature = "reqwest")]
12pub mod reqwest;
13#[cfg(feature = "tokio")]
14pub mod tokio_fs;
15
16#[cfg(feature = "reqwest")]
17pub use self::reqwest::JsonLdReqwestLoader;
18pub use chain::JsonLdChainLoader;
19pub use fs::JsonLdFsLoader;
20pub use map::StaticJsonLdLoader;
21pub use none::NoJsonLdLoader;
22#[cfg(feature = "tokio")]
23pub use tokio_fs::JsonLdTokioFsLoader;
24
25pub type RemoteJsonLdContext = RemoteJsonLdDocument<JsonLdContextDocumentValue>;
27
28#[derive(Clone)]
32pub enum RemoteJsonLdDocument<T = JsonValue> {
33 Iri(IriBuf),
35
36 Loaded(JsonLdDocument<T>),
38}
39
40impl<T> RemoteJsonLdDocument<T> {
41 pub fn iri(iri: IriBuf) -> Self {
46 Self::Iri(iri)
47 }
48}
49
50impl<T> RemoteJsonLdDocument<T> {
51 pub fn url(&self) -> Option<&Iri> {
52 match self {
53 Self::Iri(iri) => Some(iri),
54 Self::Loaded(t) => t.url(),
55 }
56 }
57}
58
59impl<T> RemoteJsonLdDocument<T>
60where
61 T: TryFrom<JsonValue>,
62 T::Error: Into<anyhow::Error>,
63{
64 pub async fn load(
69 self,
70 loader: &impl AsyncJsonLdLoader,
71 ) -> Result<JsonLdDocument<T>, JsonLdLoadError> {
72 match self {
73 Self::Iri(r) => loader
74 .async_load(&r)
75 .await?
76 .try_map(TryInto::try_into)
77 .map_err(|e| JsonLdLoadError::new(r, e)),
78 Self::Loaded(doc) => Ok(doc),
79 }
80 }
81
82 pub async fn loaded(
89 &self,
90 loader: &impl AsyncJsonLdLoader,
91 ) -> Result<Cow<'_, JsonLdDocument<T>>, JsonLdLoadError>
92 where
93 T: Clone,
94 {
95 match self {
96 Self::Iri(r) => loader
97 .async_load(r)
98 .await?
99 .try_map(TryInto::try_into)
100 .map_err(|e| JsonLdLoadError::new(r.clone(), e))
101 .map(Cow::Owned),
102 Self::Loaded(doc) => Ok(Cow::Borrowed(doc)),
103 }
104 }
105}
106
107#[derive(Debug, thiserror::Error)]
109#[error("loading document `{target}` failed: {cause}")]
110pub struct JsonLdLoadError {
111 pub target: IriBuf,
112 pub cause: anyhow::Error,
113}
114
115impl JsonLdLoadError {
116 pub fn new(target: IriBuf, cause: impl Into<anyhow::Error>) -> Self {
117 Self {
118 target,
119 cause: cause.into(),
120 }
121 }
122}
123
124pub trait AsyncJsonLdLoader {
144 #[allow(async_fn_in_trait)]
146 async fn async_load(&self, url: &Iri) -> Result<JsonLdDocument, JsonLdLoadError>;
147}
148
149impl<L: AsyncJsonLdLoader> AsyncJsonLdLoader for &L {
150 async fn async_load(&self, url: &Iri) -> Result<JsonLdDocument, JsonLdLoadError> {
151 L::async_load(self, url).await
152 }
153}
154
155impl<L: AsyncJsonLdLoader> AsyncJsonLdLoader for &mut L {
156 async fn async_load(&self, url: &Iri) -> Result<JsonLdDocument, JsonLdLoadError> {
157 L::async_load(self, url).await
158 }
159}
160
161impl<L: AsyncJsonLdLoader, F: FnOnce() -> L> AsyncJsonLdLoader for LazyLock<L, F> {
163 async fn async_load(&self, url: &Iri) -> Result<JsonLdDocument, JsonLdLoadError> {
164 L::async_load(self, url).await
165 }
166}
167
168pub trait JsonLdLoader {
169 fn load(&self, url: &Iri) -> Result<JsonLdDocument, JsonLdLoadError>;
171
172 fn as_async_loader(&self) -> &ToAsyncJsonLdLoader<Self> {
174 ToAsyncJsonLdLoader::from_ref(self)
175 }
176
177 fn into_async_loader(self) -> ToAsyncJsonLdLoader<Self>
179 where
180 Self: Sized,
181 {
182 ToAsyncJsonLdLoader(self)
183 }
184}
185
186impl<L: JsonLdLoader> JsonLdLoader for &L {
187 fn load(&self, url: &Iri) -> Result<JsonLdDocument, JsonLdLoadError> {
188 L::load(self, url)
189 }
190}
191
192impl<L: JsonLdLoader> JsonLdLoader for &mut L {
193 fn load(&self, url: &Iri) -> Result<JsonLdDocument, JsonLdLoadError> {
194 L::load(self, url)
195 }
196}
197
198impl<L: JsonLdLoader, F: FnOnce() -> L> JsonLdLoader for LazyLock<L, F> {
200 fn load(&self, url: &Iri) -> Result<JsonLdDocument, JsonLdLoadError> {
201 L::load(self, url)
202 }
203}
204
205#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
206#[repr(transparent)]
207pub struct ToAsyncJsonLdLoader<T: ?Sized>(pub T);
208
209impl<T: ?Sized> ToAsyncJsonLdLoader<T> {
210 pub fn from_ref(loader: &T) -> &Self {
211 unsafe {
212 std::mem::transmute(loader)
214 }
215 }
216}
217
218impl<T: JsonLdLoader> AsyncJsonLdLoader for ToAsyncJsonLdLoader<T> {
219 async fn async_load(&self, url: &Iri) -> Result<JsonLdDocument, JsonLdLoadError> {
220 self.0.load(url)
221 }
222}