apub_core/
repo.rs

1//! Traits describing the fetching of objects
2
3use crate::session::Session;
4
5use std::{rc::Rc, sync::Arc};
6use url::Url;
7
8/// A Repository from which objects can be dereferenced
9///
10/// This can describe both HTTP remotes, e.g. for fetching remote ActivityPub objects, as well as
11/// for fetching local objects from a database
12///
13/// ```rust
14/// use apub_core::{repo::{Dereference, Repo}, session::Session};
15/// use std::{collections::HashMap, sync::{Arc, Mutex}};
16/// use url::Url;
17///
18/// /// An in-memory repository for objects
19/// pub struct MemoryRepo {
20///     inner: Arc<Mutex<HashMap<Url, serde_json::Value>>>,
21/// }
22///
23/// #[async_trait::async_trait(?Send)]
24/// impl Repo for MemoryRepo {
25///     type Error = serde_json::Error;
26///
27///     async fn fetch<D: Dereference, S: Session>(&self, id: D, _: S) -> Result<Option<D::Output>, Self::Error> {
28///         if let Some(value) = self.inner.lock().unwrap().get(id.url()) {
29///             serde_json::from_value(value.clone()).map(Some)
30///         } else {
31///             Ok(None)
32///         }
33///     }
34/// }
35/// ```
36#[async_trait::async_trait(?Send)]
37pub trait Repo {
38    /// The Error produced by fetching an object
39    type Error: 'static;
40
41    /// Fetch the object from the repository
42    async fn fetch<D: Dereference, S: Session>(
43        &self,
44        id: D,
45        session: S,
46    ) -> Result<Option<D::Output>, Self::Error>;
47}
48
49/// A type used to produce Repos
50pub trait RepoFactory {
51    /// The Reop type to be produced
52    type Repo: Repo;
53
54    /// Cryptography used to sign requests
55    type Crypto;
56
57    /// Produce the Repo
58    fn build_repo(&self, crypto: Self::Crypto) -> Self::Repo;
59}
60
61/// A trait describing the input and output types of a dereference operation
62///
63/// For example, a type ObjectId<T> can be created that contains a simple Url, and with a
64/// dereference implementation, can be passed to a Repository to fetch the T object it represents
65///
66/// ```rust
67/// use apub_core::repo::{Dereference, Repo};
68/// use std::borrow::Cow;
69/// use url::Url;
70///
71/// #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
72/// struct SomeId<'a>(Cow<'a, Url>);
73///
74/// #[derive(Debug, serde::Deserialize, serde::Serialize)]
75/// struct SomeObject {
76///     id: SomeId<'static>,
77///     content: String,
78/// }
79///
80/// impl<'a> Dereference for SomeId<'a> {
81///     type Output = SomeObject;
82///
83///     fn url(&self) -> &Url {
84///         &self.0
85///     }
86/// }
87///
88/// async fn fetch<R: Repo>(repo: &R, url: &Url) -> Option<SomeObject> {
89///     let id = SomeId(Cow::Borrowed(url));
90///     repo.fetch(id, ()).await.ok()?
91/// }
92/// ```
93pub trait Dereference {
94    /// The Concrete Type produced by dereferencing
95    type Output: serde::de::DeserializeOwned;
96
97    /// Fetch the URL that describes the object
98    fn url(&self) -> &Url;
99}
100
101impl<'a, T> Dereference for &'a T
102where
103    T: Dereference,
104{
105    type Output = T::Output;
106
107    fn url(&self) -> &Url {
108        T::url(self)
109    }
110}
111
112impl<'a, T> Dereference for &'a mut T
113where
114    T: Dereference,
115{
116    type Output = T::Output;
117
118    fn url(&self) -> &Url {
119        T::url(self)
120    }
121}
122
123impl<T> Dereference for Box<T>
124where
125    T: Dereference,
126{
127    type Output = T::Output;
128
129    fn url(&self) -> &Url {
130        T::url(self)
131    }
132}
133
134impl<T> Dereference for Rc<T>
135where
136    T: Dereference,
137{
138    type Output = T::Output;
139
140    fn url(&self) -> &Url {
141        T::url(self)
142    }
143}
144
145impl<T> Dereference for Arc<T>
146where
147    T: Dereference,
148{
149    type Output = T::Output;
150
151    fn url(&self) -> &Url {
152        T::url(self)
153    }
154}
155
156#[async_trait::async_trait(?Send)]
157impl<'a, T> Repo for &'a T
158where
159    T: Repo,
160{
161    type Error = T::Error;
162
163    async fn fetch<D: Dereference, S: Session>(
164        &self,
165        id: D,
166        session: S,
167    ) -> Result<Option<D::Output>, Self::Error> {
168        T::fetch(self, id, session).await
169    }
170}
171
172#[async_trait::async_trait(?Send)]
173impl<'a, T> Repo for &'a mut T
174where
175    T: Repo,
176{
177    type Error = T::Error;
178
179    async fn fetch<D: Dereference, S: Session>(
180        &self,
181        id: D,
182        session: S,
183    ) -> Result<Option<D::Output>, Self::Error> {
184        T::fetch(self, id, session).await
185    }
186}
187
188#[async_trait::async_trait(?Send)]
189impl<T> Repo for Box<T>
190where
191    T: Repo,
192{
193    type Error = T::Error;
194
195    async fn fetch<D: Dereference, S: Session>(
196        &self,
197        id: D,
198        session: S,
199    ) -> Result<Option<D::Output>, Self::Error> {
200        T::fetch(self, id, session).await
201    }
202}
203
204#[async_trait::async_trait(?Send)]
205impl<T> Repo for Rc<T>
206where
207    T: Repo,
208{
209    type Error = T::Error;
210
211    async fn fetch<D: Dereference, S: Session>(
212        &self,
213        id: D,
214        session: S,
215    ) -> Result<Option<D::Output>, Self::Error> {
216        T::fetch(self, id, session).await
217    }
218}
219
220#[async_trait::async_trait(?Send)]
221impl<T> Repo for Arc<T>
222where
223    T: Repo,
224{
225    type Error = T::Error;
226
227    async fn fetch<D: Dereference, S: Session>(
228        &self,
229        id: D,
230        session: S,
231    ) -> Result<Option<D::Output>, Self::Error> {
232        T::fetch(self, id, session).await
233    }
234}