use std::sync::Arc;
use async_trait::async_trait;
use tokio::sync::Semaphore;
use uuid::Uuid;
use crate::{StorageError, StorageRead, StorageResult};
#[async_trait]
pub trait Loadable<S>: Sized + Send + Sync {
async fn load(storage: &dyn StorageRead, scope: &S) -> StorageResult<Self>;
}
pub struct LoadMetadata {
pub load_id: Uuid,
pub sequence_number: u64,
}
pub struct LoadResult<T> {
pub data: T,
pub metadata: LoadMetadata,
}
pub struct LoadSpec<T: Loadable<S>, S> {
pub storage: Arc<dyn StorageRead>,
pub metadata: Option<LoadMetadata>,
_phantom: std::marker::PhantomData<(T, S)>,
}
pub struct Loader {
semaphore: Arc<Semaphore>,
}
impl Loader {
pub fn new(max_concurrent_loads: usize) -> Self {
Self {
semaphore: Arc::new(Semaphore::new(max_concurrent_loads)),
}
}
pub async fn load<T: Loadable<S>, S>(
&self,
spec: LoadSpec<T, S>,
scope: &S,
) -> StorageResult<LoadResult<T>> {
let _permit = self
.semaphore
.acquire()
.await
.map_err(|_| StorageError::from_storage("Semaphore closed"))?;
let metadata = spec.metadata.unwrap_or_else(|| LoadMetadata {
load_id: Uuid::new_v4(),
sequence_number: 0,
});
let data = T::load(&*spec.storage, scope).await?;
Ok(LoadResult { data, metadata })
}
}