use std::{fmt::Debug, ops::Range};
use super::{ExactLoader, LoadedItems, Loader, MemoryLoader, PaginatedCount, PaginatedLoader};
pub trait InternalLoader<M> {
const CHUNK_SIZE: Option<usize> = None;
type Item;
type Query;
type Error: Debug + 'static;
fn load_items(
&self,
range: Range<usize>,
query: &Self::Query,
) -> impl Future<Output = Result<LoadedItems<Self::Item>, Self::Error>> {
let corrected_range = if let Some(chunk_size) = Self::CHUNK_SIZE {
let Range { start, end } = range;
let chunk_start = (start / chunk_size) * chunk_size;
let chunk_end = end.div_ceil(chunk_size) * chunk_size;
chunk_start..chunk_end
} else {
range
};
self.load_items_inner(corrected_range, query)
}
fn load_items_inner(
&self,
range: Range<usize>,
query: &Self::Query,
) -> impl Future<Output = Result<LoadedItems<Self::Item>, Self::Error>>;
fn item_count(
&self,
_query: &Self::Query,
) -> impl Future<Output = Result<Option<usize>, Self::Error>> {
async { Ok(None) }
}
}
pub struct LoaderMarker;
impl<L> InternalLoader<LoaderMarker> for L
where
L: Loader,
{
const CHUNK_SIZE: Option<usize> = L::CHUNK_SIZE;
type Item = L::Item;
type Query = L::Query;
type Error = L::Error;
#[inline]
async fn load_items_inner(
&self,
range: Range<usize>,
query: &Self::Query,
) -> Result<LoadedItems<Self::Item>, Self::Error> {
Loader::load_items(self, range, query).await
}
#[inline]
async fn item_count(&self, query: &Self::Query) -> Result<Option<usize>, Self::Error> {
Loader::item_count(self, query).await
}
}
pub struct ExactLoaderMarker;
impl<L> InternalLoader<ExactLoaderMarker> for L
where
L: ExactLoader,
{
type Item = L::Item;
type Query = L::Query;
type Error = L::Error;
#[inline]
async fn load_items_inner(
&self,
range: Range<usize>,
query: &Self::Query,
) -> Result<LoadedItems<Self::Item>, Self::Error> {
ExactLoader::load_items(self, range.clone(), query)
.await
.map(|items| LoadedItems { items, range })
}
#[inline]
async fn item_count(&self, query: &Self::Query) -> Result<Option<usize>, Self::Error> {
ExactLoader::item_count(self, query).await
}
}
pub struct MemoryLoaderMarker;
impl<L> InternalLoader<MemoryLoaderMarker> for L
where
L: MemoryLoader,
{
type Item = L::Item;
type Query = L::Query;
type Error = ();
#[inline]
async fn load_items_inner(
&self,
range: Range<usize>,
query: &Self::Query,
) -> Result<LoadedItems<Self::Item>, Self::Error> {
Ok(LoadedItems {
items: self.load_items(range.clone(), query),
range,
})
}
#[inline]
async fn item_count(&self, query: &Self::Query) -> Result<Option<usize>, Self::Error> {
Ok(Some(MemoryLoader::item_count(self, query)))
}
}
pub struct PaginatedLoaderMarker;
impl<L> InternalLoader<PaginatedLoaderMarker> for L
where
L: PaginatedLoader,
{
const CHUNK_SIZE: Option<usize> = Some(L::PAGE_ITEM_COUNT);
type Item = L::Item;
type Query = L::Query;
type Error = L::Error;
#[inline]
async fn load_items_inner(
&self,
range: Range<usize>,
query: &Self::Query,
) -> Result<LoadedItems<Self::Item>, Self::Error> {
let Range { start, end } = range;
debug_assert_eq!(start % L::PAGE_ITEM_COUNT, 0);
debug_assert_eq!((end - start) % L::PAGE_ITEM_COUNT, 0);
let mut loaded = Vec::with_capacity(end - start);
for cur_start in (start..end).step_by(L::PAGE_ITEM_COUNT) {
loaded.extend(
self.load_page(cur_start / L::PAGE_ITEM_COUNT, query)
.await?,
);
}
let len = loaded.len();
Ok(LoadedItems {
items: loaded,
range: start..start + len,
})
}
#[inline]
async fn item_count(&self, query: &Self::Query) -> Result<Option<usize>, Self::Error> {
PaginatedLoader::count(self, query).await.map(|count| {
count.map(|count| match count {
PaginatedCount::Items(item_count) => item_count,
PaginatedCount::Pages(page_count) => page_count * L::PAGE_ITEM_COUNT,
})
})
}
}