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#[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}