do_paginate/
lib.rs

1use std::cmp::{max, min};
2
3use std::fmt;
4
5#[derive(Debug)]
6pub struct OutOfBound;
7
8impl fmt::Display for OutOfBound {
9    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
10        write!(f, "out of bound")
11    }
12}
13
14// page_number (offset) is 0-indexed
15
16#[derive(Clone, Debug, Eq, PartialEq, Copy)]
17pub struct Pages {
18    page_number: usize,
19    length: usize,
20    per_page: usize,
21}
22
23impl Pages {
24    pub fn new(length: usize, per_page: usize) -> Pages {
25        Pages {
26            page_number: 0,
27            length,
28            per_page,
29        }
30    }
31
32    pub fn to_page_number(&self, page_number: usize) -> Result<Page, OutOfBound> {
33        let mut page = Page::default();
34
35        if page_number >= self.page_count() {
36            return Err(OutOfBound);
37        }
38        page.page_number = page_number;
39        page.begin = min(page.page_number * self.per_page, self.length);
40        page.end = min(page.begin + self.per_page, self.length);
41        page.length = max(page.end - page.begin, 0);
42
43        if page.length == 0 {
44            page.begin = 0;
45            page.end = 0;
46        };
47        if page.length > 0 {
48            page.end -= 1;
49        };
50
51        Ok(page)
52    }
53
54    pub fn offset(&self) -> usize {
55        self.page_number
56    }
57
58    pub fn length(&self) -> usize {
59        self.length
60    }
61
62    pub fn per_page(&self) -> usize {
63        self.per_page
64    }
65
66    pub fn page_count(&self) -> usize {
67        (self.length + self.per_page - 1) / self.per_page
68    }
69}
70
71impl Iterator for Pages {
72    type Item = Page;
73    fn next(&mut self) -> Option<Self::Item> {
74        let page: Option<Page> = match self.to_page_number(self.page_number) {
75            Ok(page) => Some(page),
76            Err(_msg) => None,
77        };
78        self.page_number += 1;
79        page
80    }
81}
82
83impl IntoIterator for &Pages {
84    type Item = Page;
85    type IntoIter = Pages;
86
87    fn into_iter(self) -> Pages {
88        Pages {
89            page_number: 0,
90            length: self.length(),
91            per_page: self.per_page(),
92        }
93    }
94}
95
96#[derive(Clone, Debug, Eq, PartialEq, Default)]
97pub struct Page {
98    pub page_number: usize,
99    pub length: usize,
100    pub begin: usize,
101    pub end: usize,
102}
103
104impl Page {
105    pub fn is_empty(&self) -> bool {
106        self.length == 0
107    }
108}
109
110#[cfg(test)]
111mod tests {
112
113    use super::{Page, Pages};
114
115    fn get_url() -> String {
116        "www.test.com/".to_string()
117    }
118
119    #[test]
120    fn test_iter() {
121        let pages = Pages::new(6, 2);
122        let mut pages_iter = pages.into_iter();
123        assert_eq!(
124            pages_iter.next(),
125            Some(Page {
126                page_number: 0,
127                length: 2,
128                begin: 0,
129                end: 1,
130            })
131        );
132        assert_eq!(
133            pages_iter.next(),
134            Some(Page {
135                page_number: 1,
136                length: 2,
137                begin: 2,
138                end: 3,
139            })
140        );
141        assert_eq!(
142            pages_iter.next(),
143            Some(Page {
144                page_number: 2,
145                length: 2,
146                begin: 4,
147                end: 5,
148            })
149        );
150        assert_eq!(pages_iter.next(), None);
151    }
152
153    #[test]
154    fn default_page() {
155        let page = Page::default();
156        assert_eq!(
157            page,
158            Page {
159                page_number: 0,
160                length: 0,
161                begin: 0,
162                end: 0,
163            }
164        );
165    }
166
167    #[test]
168    fn no_function_passing() {
169        let total_items = 10usize;
170        let items_per_page = 5usize;
171
172        let pages = Pages::new(total_items, items_per_page);
173        assert_eq!(
174            match pages.to_page_number(0) {
175                Ok(page) => page,
176                Err(msg) => {
177                    eprint!("{}", msg);
178                    Page::default()
179                }
180            },
181            Page {
182                page_number: 0,
183                length: 5,
184                begin: 0,
185                end: 4,
186            }
187        );
188        assert_eq!(
189            match pages.to_page_number(1) {
190                Ok(page) => page,
191                Err(msg) => {
192                    eprint!("{}", msg);
193                    Page::default()
194                }
195            },
196            Page {
197                page_number: 1,
198                length: 5,
199                begin: 5,
200                end: 9,
201            }
202        );
203    }
204
205    #[test]
206    fn out_of_bound() {
207        let total_items = 0usize;
208        let items_per_page = 5usize;
209        let pages = Pages::new(total_items, items_per_page);
210        let page = match pages.to_page_number(1) {
211            Ok(page) => page,
212            Err(msg) => {
213                eprint!("{}", msg);
214                Page::default()
215            }
216        };
217        assert_eq!(
218            page,
219            Page {
220                page_number: 0,
221                length: 0,
222                begin: 0,
223                end: 0,
224            }
225        );
226    }
227
228    #[test]
229    fn empty_page() {
230        let total_items = 0usize;
231        let items_per_page = 5usize;
232        let pages = Pages::new(total_items, items_per_page);
233        assert_eq!(
234            match pages.to_page_number(0) {
235                Ok(page) => page,
236                Err(msg) => {
237                    eprint!("{}", msg);
238                    Page::default()
239                }
240            },
241            Page {
242                page_number: 0,
243                length: 0,
244                begin: 0,
245                end: 0,
246            }
247        );
248    }
249
250    #[test]
251    fn single_page() {
252        let total_items = 5usize;
253        let items_per_page = 5usize;
254        let pages = Pages::new(total_items, items_per_page);
255        assert_eq!(
256            match pages.to_page_number(0) {
257                Ok(page) => page,
258                Err(msg) => {
259                    eprint!("{}", msg);
260                    Page::default()
261                }
262            },
263            Page {
264                page_number: 0,
265                length: 5,
266                begin: 0,
267                end: 4,
268            }
269        );
270        assert_eq!(
271            match pages.to_page_number(1) {
272                Ok(page) => page,
273                Err(msg) => {
274                    eprint!("{}", msg);
275                    Page::default()
276                }
277            },
278            Page {
279                page_number: 0,
280                length: 0,
281                begin: 0,
282                end: 0,
283            }
284        );
285    }
286
287    #[test]
288    fn single_item() {
289        let total_items = 1usize;
290        let items_per_page = 5usize;
291
292        let pages = Pages::new(total_items, items_per_page);
293        assert_eq!(
294            match pages.to_page_number(0) {
295                Ok(page) => page,
296                Err(msg) => {
297                    eprint!("{}", msg);
298                    Page::default()
299                }
300            },
301            Page {
302                page_number: 0,
303                length: 1,
304                begin: 0,
305                end: 0,
306            }
307        );
308        assert_eq!(
309            match pages.to_page_number(1) {
310                Ok(page) => page,
311                Err(msg) => {
312                    eprint!("{}", msg);
313                    Page::default()
314                }
315            },
316            Page {
317                page_number: 0,
318                length: 0,
319                begin: 0,
320                end: 0,
321            }
322        );
323    }
324
325    #[test]
326    fn odd_items() {
327        let total_items = 5usize;
328        let items_per_page = 2usize;
329
330        let pages = Pages::new(total_items, items_per_page);
331        assert_eq!(
332            match pages.to_page_number(0) {
333                Ok(page) => page,
334                Err(msg) => {
335                    eprint!("{}", msg);
336                    Page::default()
337                }
338            },
339            Page {
340                page_number: 0,
341                length: 2,
342                begin: 0,
343                end: 1,
344            }
345        );
346        assert_eq!(
347            match pages.to_page_number(1) {
348                Ok(page) => page,
349                Err(msg) => {
350                    eprint!("{}", msg);
351                    Page::default()
352                }
353            },
354            Page {
355                page_number: 1,
356                length: 2,
357                begin: 2,
358                end: 3,
359            }
360        );
361        assert_eq!(
362            match pages.to_page_number(2) {
363                Ok(page) => page,
364                Err(msg) => {
365                    eprint!("{}", msg);
366                    Page::default()
367                }
368            },
369            Page {
370                page_number: 2,
371                length: 1,
372                begin: 4,
373                end: 4,
374            }
375        );
376        assert_eq!(
377            match pages.to_page_number(3) {
378                Ok(page) => page,
379                Err(msg) => {
380                    eprint!("{}", msg);
381                    Page::default()
382                }
383            },
384            Page {
385                page_number: 0,
386                length: 0,
387                begin: 0,
388                end: 0,
389            }
390        );
391    }
392
393    #[test]
394    fn even_items() {
395        let total_items = 6usize;
396        let items_per_page = 2usize;
397
398        let pages = Pages::new(total_items, items_per_page);
399
400        assert_eq!(
401            match pages.to_page_number(0) {
402                Ok(page) => page,
403                Err(msg) => {
404                    eprint!("{}", msg);
405                    Page::default()
406                }
407            },
408            Page {
409                page_number: 0,
410                length: 2,
411                begin: 0,
412                end: 1,
413            }
414        );
415        assert_eq!(
416            match pages.to_page_number(1) {
417                Ok(page) => page,
418                Err(msg) => {
419                    eprint!("{}", msg);
420                    Page::default()
421                }
422            },
423            Page {
424                page_number: 1,
425                length: 2,
426                begin: 2,
427                end: 3,
428            }
429        );
430        assert_eq!(
431            match pages.to_page_number(2) {
432                Ok(page) => page,
433                Err(msg) => {
434                    eprint!("{}", msg);
435                    Page::default()
436                }
437            },
438            Page {
439                page_number: 2,
440                length: 2,
441                begin: 4,
442                end: 5,
443            }
444        );
445        assert_eq!(
446            match pages.to_page_number(3) {
447                Ok(page) => page,
448                Err(msg) => {
449                    eprint!("{}", msg);
450                    Page::default()
451                }
452            },
453            Page {
454                page_number: 0,
455                length: 0,
456                begin: 0,
457                end: 0,
458            }
459        );
460    }
461
462    #[test]
463    fn odd_sizes() {
464        let total_items = 5usize;
465        let items_per_page = 3usize;
466        let pages = Pages::new(total_items, items_per_page);
467        assert_eq!(
468            match pages.to_page_number(0) {
469                Ok(page) => page,
470                Err(msg) => {
471                    eprint!("{}", msg);
472                    Page::default()
473                }
474            },
475            Page {
476                page_number: 0,
477                length: 3,
478                begin: 0,
479                end: 2,
480            }
481        );
482        assert_eq!(
483            match pages.to_page_number(1) {
484                Ok(page) => page,
485                Err(msg) => {
486                    eprint!("{}", msg);
487                    Page::default()
488                }
489            },
490            Page {
491                page_number: 1,
492                length: 2,
493                begin: 3,
494                end: 4,
495            }
496        );
497        assert_eq!(
498            match pages.to_page_number(2) {
499                Ok(page) => page,
500                Err(msg) => {
501                    eprint!("{}", msg);
502                    Page::default()
503                }
504            },
505            Page {
506                page_number: 0,
507                length: 0,
508                begin: 0,
509                end: 0,
510            }
511        );
512    }
513
514    #[test]
515    fn iterator() {
516        let total_items = 1usize;
517        let items_per_page = 1usize;
518
519        let pages = Pages::new(total_items, items_per_page);
520        for p in pages {
521            assert_eq!(
522                p,
523                Page {
524                    page_number: 0,
525                    length: 1,
526                    begin: 0,
527                    end: 0,
528                }
529            );
530        }
531    }
532
533    #[test]
534    fn iterator_ref() {
535        let total_items = 1usize;
536        let items_per_page = 1usize;
537        let pages = Pages::new(total_items, items_per_page);
538        for p in &pages {
539            assert_eq!(
540                p,
541                Page {
542                    page_number: 0,
543                    length: 1,
544                    begin: 0,
545                    end: 0,
546                }
547            );
548        }
549    }
550
551    #[test]
552    fn is_empty() {
553        let empty_page = Page::default();
554        assert!(empty_page.is_empty());
555
556        let filled_page = Page {
557            length: 1,
558            ..Page::default()
559        };
560        assert!(!filled_page.is_empty());
561    }
562
563    #[test]
564    fn offset() {
565        let pages = Pages::new(100, 5);
566        assert_eq!(0, pages.offset());
567    }
568
569    #[test]
570    fn length() {
571        let pages = Pages::new(100, 5);
572        assert_eq!(100, pages.length());
573    }
574
575    #[test]
576    fn limit() {
577        let pages = Pages::new(100, 5);
578        assert_eq!(5, pages.per_page());
579    }
580
581    #[test]
582    fn page_count() {
583        let pages = Pages::new(100, 5);
584        assert_eq!(20, pages.page_count());
585
586        let pages = Pages::new(101, 5);
587        assert_eq!(21, pages.page_count());
588
589        let pages = Pages::new(99, 5);
590        assert_eq!(20, pages.page_count());
591    }
592}