1use std::cmp::{max, min};
35
36#[derive(Clone, Debug, Eq, PartialEq)]
39pub struct Pages {
40 offset: usize,
42 length: usize,
44 limit: usize,
46}
47
48impl Pages {
49 pub fn new(length: usize, limit: usize) -> Pages {
56 Pages {
57 offset: 0,
58 length,
59 limit,
60 }
61 }
62
63 pub fn with_offset(&self, offset: usize) -> Page {
69 let mut page = Page::default();
70 page.offset = offset;
71 page.start = min(page.offset * self.limit, self.length);
72 page.end = min(page.start + self.limit, self.length);
73 page.length = max(page.end - page.start, 0);
74 if page.length == 0 {
75 page.start = 0;
76 page.end = 0;
77 };
78 if page.length > 0 {
79 page.end -= 1;
80 };
81 page
82 }
83
84 pub fn offset(&self) -> usize {
86 self.offset
87 }
88
89 pub fn length(&self) -> usize {
91 self.length
92 }
93
94 pub fn limit(&self) -> usize {
96 self.limit
97 }
98
99 pub fn page_count(&self) -> usize {
101 (self.length + self.limit - 1) / self.limit
102 }
103}
104
105impl Iterator for Pages {
106 type Item = Page;
107 fn next(&mut self) -> Option<Self::Item> {
108 let page: Page = self.with_offset(self.offset);
109 self.offset += 1;
110 if page.is_empty() {
111 None
112 } else {
113 Some(page)
114 }
115 }
116}
117
118impl IntoIterator for &Pages {
119 type Item = Page;
120 type IntoIter = Pages;
121
122 fn into_iter(self) -> Pages {
123 self.clone()
124 }
125}
126
127#[derive(Clone, Debug, Eq, PartialEq)]
129pub struct Page {
130 pub offset: usize,
132 pub length: usize,
134 pub start: usize,
136 pub end: usize,
138}
139
140impl Page {
141 pub fn is_empty(&self) -> bool {
143 self.length == 0
144 }
145}
146
147impl Default for Page {
148 fn default() -> Self {
150 Page {
151 offset: 0usize,
152 length: 0usize,
153 start: 0usize,
154 end: 0usize,
155 }
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::{Page, Pages};
162
163 #[test]
164 fn default_page() {
165 let page = Page::default();
166 assert_eq!(
167 page,
168 Page {
169 offset: 0,
170 length: 0,
171 start: 0,
172 end: 0
173 }
174 );
175 }
176
177 #[test]
178 fn empty_page() {
179 let total_items = 0usize;
180 let items_per_page = 5usize;
181 let pages = Pages::new(total_items, items_per_page);
182 assert_eq!(
183 pages.with_offset(0),
184 Page {
185 offset: 0,
186 length: 0,
187 start: 0,
188 end: 0
189 }
190 );
191 assert_eq!(
192 pages.with_offset(1),
193 Page {
194 offset: 1,
195 length: 0,
196 start: 0,
197 end: 0
198 }
199 );
200 }
201
202 #[test]
203 fn limitless_page() {
204 let total_items = 5usize;
205 let items_per_page = 0usize;
206 let pages = Pages::new(total_items, items_per_page);
207 assert_eq!(
208 pages.with_offset(0),
209 Page {
210 offset: 0,
211 length: 0,
212 start: 0,
213 end: 0
214 }
215 );
216 assert_eq!(
217 pages.with_offset(1),
218 Page {
219 offset: 1,
220 length: 0,
221 start: 0,
222 end: 0
223 }
224 );
225 }
226
227 #[test]
228 fn single_page() {
229 let total_items = 5usize;
230 let items_per_page = 5usize;
231 let pages = Pages::new(total_items, items_per_page);
232 assert_eq!(
233 pages.with_offset(0),
234 Page {
235 offset: 0,
236 length: 5,
237 start: 0,
238 end: 4
239 }
240 );
241 assert_eq!(
242 pages.with_offset(1),
243 Page {
244 offset: 1,
245 length: 0,
246 start: 0,
247 end: 0
248 }
249 );
250 assert_eq!(
251 pages.with_offset(2),
252 Page {
253 offset: 2,
254 length: 0,
255 start: 0,
256 end: 0
257 }
258 );
259 }
260
261 #[test]
262 fn single_item() {
263 let total_items = 1usize;
264 let items_per_page = 5usize;
265 let pages = Pages::new(total_items, items_per_page);
266 assert_eq!(
267 pages.with_offset(0),
268 Page {
269 offset: 0,
270 length: 1,
271 start: 0,
272 end: 0
273 }
274 );
275 assert_eq!(
276 pages.with_offset(1),
277 Page {
278 offset: 1,
279 length: 0,
280 start: 0,
281 end: 0
282 }
283 );
284 }
285
286 #[test]
287 fn odd_items() {
288 let total_items = 5usize;
289 let items_per_page = 2usize;
290 let pages = Pages::new(total_items, items_per_page);
291 assert_eq!(
292 pages.with_offset(0),
293 Page {
294 offset: 0,
295 length: 2,
296 start: 0,
297 end: 1
298 }
299 );
300 assert_eq!(
301 pages.with_offset(1),
302 Page {
303 offset: 1,
304 length: 2,
305 start: 2,
306 end: 3
307 }
308 );
309 assert_eq!(
310 pages.with_offset(2),
311 Page {
312 offset: 2,
313 length: 1,
314 start: 4,
315 end: 4
316 }
317 );
318 assert_eq!(
319 pages.with_offset(3),
320 Page {
321 offset: 3,
322 length: 0,
323 start: 0,
324 end: 0
325 }
326 );
327 }
328
329 #[test]
330 fn even_items() {
331 let total_items = 6usize;
332 let items_per_page = 2usize;
333 let pages = Pages::new(total_items, items_per_page);
334 assert_eq!(
335 pages.with_offset(0),
336 Page {
337 offset: 0,
338 length: 2,
339 start: 0,
340 end: 1
341 }
342 );
343 assert_eq!(
344 pages.with_offset(1),
345 Page {
346 offset: 1,
347 length: 2,
348 start: 2,
349 end: 3
350 }
351 );
352 assert_eq!(
353 pages.with_offset(2),
354 Page {
355 offset: 2,
356 length: 2,
357 start: 4,
358 end: 5
359 }
360 );
361 assert_eq!(
362 pages.with_offset(3),
363 Page {
364 offset: 3,
365 length: 0,
366 start: 0,
367 end: 0
368 }
369 );
370 }
371
372 #[test]
373 fn odd_sizes() {
374 let total_items = 5usize;
375 let items_per_page = 3usize;
376 let pages = Pages::new(total_items, items_per_page);
377 assert_eq!(
378 pages.with_offset(0),
379 Page {
380 offset: 0,
381 length: 3,
382 start: 0,
383 end: 2
384 }
385 );
386 assert_eq!(
387 pages.with_offset(1),
388 Page {
389 offset: 1,
390 length: 2,
391 start: 3,
392 end: 4
393 }
394 );
395 assert_eq!(
396 pages.with_offset(2),
397 Page {
398 offset: 2,
399 length: 0,
400 start: 0,
401 end: 0
402 }
403 );
404 }
405
406 #[test]
407 fn iterator() {
408 let total_items = 1usize;
409 let items_per_page = 1usize;
410 let pages = Pages::new(total_items, items_per_page);
411 for p in pages {
412 assert_eq!(
413 p,
414 Page {
415 offset: 0,
416 length: 1,
417 start: 0,
418 end: 0
419 }
420 );
421 }
422 }
423
424 #[test]
425 fn iterator_ref() {
426 let total_items = 1usize;
427 let items_per_page = 1usize;
428 let pages = Pages::new(total_items, items_per_page);
429 for p in &pages {
430 assert_eq!(
431 p,
432 Page {
433 offset: 0,
434 length: 1,
435 start: 0,
436 end: 0
437 }
438 );
439 }
440 }
441
442 #[test]
443 fn is_empty() {
444 let empty_page = Page::default();
445 assert!(empty_page.is_empty());
446
447 let filled_page = Page {
448 length: 1,
449 ..Page::default()
450 };
451 assert!(!filled_page.is_empty());
452 }
453
454 #[test]
455 fn offset() {
456 let pages = Pages::new(100, 5);
457 assert_eq!(0, pages.offset());
458 }
459
460 #[test]
461 fn length() {
462 let pages = Pages::new(100, 5);
463 assert_eq!(100, pages.length());
464 }
465
466 #[test]
467 fn limit() {
468 let pages = Pages::new(100, 5);
469 assert_eq!(5, pages.limit());
470 }
471
472 #[test]
473 fn page_count() {
474 let pages = Pages::new(100, 5);
475 assert_eq!(20, pages.page_count());
476
477 let pages = Pages::new(101, 5);
478 assert_eq!(21, pages.page_count());
479
480 let pages = Pages::new(99, 5);
481 assert_eq!(20, pages.page_count());
482 }
483}