leptos_windowing/loaders/
internal_loader.rs1use std::{fmt::Debug, ops::Range};
2
3use super::{ExactLoader, LoadedItems, Loader, MemoryLoader, PaginatedCount, PaginatedLoader};
4
5pub trait InternalLoader<M> {
8 const CHUNK_SIZE: Option<usize> = None;
11
12 type Item;
14
15 type Query;
19
20 type Error: Debug + 'static;
22
23 fn load_items(
25 &self,
26 range: Range<usize>,
27 query: &Self::Query,
28 ) -> impl Future<Output = Result<LoadedItems<Self::Item>, Self::Error>> {
29 let corrected_range = if let Some(chunk_size) = Self::CHUNK_SIZE {
30 let Range { start, end } = range;
31 let chunk_start = (start / chunk_size) * chunk_size;
32 let chunk_end = end.div_ceil(chunk_size) * chunk_size;
33 chunk_start..chunk_end
34 } else {
35 range
36 };
37
38 self.load_items_inner(corrected_range, query)
39 }
40
41 fn load_items_inner(
46 &self,
47 range: Range<usize>,
48 query: &Self::Query,
49 ) -> impl Future<Output = Result<LoadedItems<Self::Item>, Self::Error>>;
50
51 fn item_count(
55 &self,
56 _query: &Self::Query,
57 ) -> impl Future<Output = Result<Option<usize>, Self::Error>> {
58 async { Ok(None) }
59 }
60}
61
62pub struct LoaderMarker;
63
64impl<L> InternalLoader<LoaderMarker> for L
65where
66 L: Loader,
67{
68 const CHUNK_SIZE: Option<usize> = L::CHUNK_SIZE;
69
70 type Item = L::Item;
71 type Query = L::Query;
72 type Error = L::Error;
73
74 #[inline]
75 async fn load_items_inner(
76 &self,
77 range: Range<usize>,
78 query: &Self::Query,
79 ) -> Result<LoadedItems<Self::Item>, Self::Error> {
80 Loader::load_items(self, range, query).await
81 }
82
83 #[inline]
84 async fn item_count(&self, query: &Self::Query) -> Result<Option<usize>, Self::Error> {
85 Loader::item_count(self, query).await
86 }
87}
88
89pub struct ExactLoaderMarker;
90
91impl<L> InternalLoader<ExactLoaderMarker> for L
92where
93 L: ExactLoader,
94{
95 type Item = L::Item;
96 type Query = L::Query;
97 type Error = L::Error;
98
99 #[inline]
100 async fn load_items_inner(
101 &self,
102 range: Range<usize>,
103 query: &Self::Query,
104 ) -> Result<LoadedItems<Self::Item>, Self::Error> {
105 ExactLoader::load_items(self, range.clone(), query)
106 .await
107 .map(|items| LoadedItems { items, range })
108 }
109
110 #[inline]
111 async fn item_count(&self, query: &Self::Query) -> Result<Option<usize>, Self::Error> {
112 ExactLoader::item_count(self, query).await
113 }
114}
115
116pub struct MemoryLoaderMarker;
117
118impl<L> InternalLoader<MemoryLoaderMarker> for L
119where
120 L: MemoryLoader,
121{
122 type Item = L::Item;
123 type Query = L::Query;
124 type Error = ();
125
126 #[inline]
127 async fn load_items_inner(
128 &self,
129 range: Range<usize>,
130 query: &Self::Query,
131 ) -> Result<LoadedItems<Self::Item>, Self::Error> {
132 Ok(LoadedItems {
133 items: self.load_items(range.clone(), query),
134 range,
135 })
136 }
137
138 #[inline]
139 async fn item_count(&self, query: &Self::Query) -> Result<Option<usize>, Self::Error> {
140 Ok(Some(MemoryLoader::item_count(self, query)))
141 }
142}
143
144pub struct PaginatedLoaderMarker;
145
146impl<L> InternalLoader<PaginatedLoaderMarker> for L
147where
148 L: PaginatedLoader,
149{
150 const CHUNK_SIZE: Option<usize> = Some(L::PAGE_ITEM_COUNT);
151
152 type Item = L::Item;
153 type Query = L::Query;
154 type Error = L::Error;
155
156 #[inline]
157 async fn load_items_inner(
158 &self,
159 range: Range<usize>,
160 query: &Self::Query,
161 ) -> Result<LoadedItems<Self::Item>, Self::Error> {
162 let Range { start, end } = range;
163
164 debug_assert_eq!(start % L::PAGE_ITEM_COUNT, 0);
165 debug_assert_eq!((end - start) % L::PAGE_ITEM_COUNT, 0);
166
167 let mut loaded = Vec::with_capacity(end - start);
168
169 for cur_start in (start..end).step_by(L::PAGE_ITEM_COUNT) {
170 loaded.extend(
171 self.load_page(cur_start / L::PAGE_ITEM_COUNT, query)
172 .await?,
173 );
174 }
175
176 let len = loaded.len();
177 Ok(LoadedItems {
178 items: loaded,
179 range: start..start + len,
180 })
181 }
182
183 #[inline]
184 async fn item_count(&self, query: &Self::Query) -> Result<Option<usize>, Self::Error> {
185 PaginatedLoader::count(self, query).await.map(|count| {
186 count.map(|count| match count {
187 PaginatedCount::Items(item_count) => item_count,
188 PaginatedCount::Pages(page_count) => page_count * L::PAGE_ITEM_COUNT,
189 })
190 })
191 }
192}