use uuid::Uuid; #[derive(Debug)] pub(crate) enum PageSource { NewerThan(Uuid), OlderThan(Uuid), } #[derive(Debug)] pub(crate) struct PageNum { pub(crate) page: usize, } #[derive(Debug)] pub(crate) struct Page { pub(crate) items: Vec, pub(crate) next: Option, pub(crate) prev: Option, pub(crate) reset: bool, } #[derive(Debug)] pub(crate) struct SearchPage { pub(crate) items: Vec, pub(crate) next: Option, pub(crate) prev: Option, pub(crate) term: String, } pub trait Pagination { fn from_max<'a>(&'a mut self, max: Uuid) -> Box + 'a>; fn from_min<'a>(&'a mut self, min: Uuid) -> Box + 'a>; fn from_start<'a>(&'a mut self) -> Box + 'a>; } pub trait SearchPagination { fn from_term<'a>(&'a mut self, term: &'a str) -> Box + 'a>; } impl Page { pub(crate) fn from_pagination( mut pagination: impl Pagination, per_page: usize, source: Option, ) -> Self { let mut items: Vec; let mut next = None; let mut prev = None; let mut reset = false; match source { Some(PageSource::OlderThan(max)) => { items = pagination.from_max(max).take(per_page + 1).collect(); if let Some(item) = items.get(0) { prev = Some(*item); } else { reset = true; } if items.len() == per_page + 1 { items.pop(); next = Some(items[per_page.saturating_sub(1)]); } } Some(PageSource::NewerThan(min)) => { let mut tmp_items: Vec<_> = pagination.from_min(min).take(per_page + 2).collect(); if tmp_items.len() == per_page + 2 { tmp_items.pop(); prev = Some(tmp_items[per_page]); } items = tmp_items.into_iter().rev().collect(); items.pop(); if let Some(item) = items.get(items.len().saturating_sub(1)) { next = Some(*item); } else { reset = true; } } None => { items = pagination.from_start().take(per_page + 1).collect(); if items.len() == per_page + 1 { items.pop(); next = Some(items[per_page.saturating_sub(1)]); } } } Page { items, next, prev, reset, } } } impl SearchPage { pub(crate) fn from_pagination( mut pagination: impl SearchPagination, per_page: usize, term: String, page: Option, ) -> Self { let mut items: Vec; let mut next = None; let mut prev = None; match page { Some(PageNum { page }) => { let page = page.saturating_sub(1); items = pagination .from_term(&term) .skip(page * per_page) .take(per_page + 1) .collect(); if page > 0 { prev = Some(page); } if items.len() == per_page + 1 { items.pop(); next = Some(page + 2); } } None => { items = pagination.from_term(&term).take(per_page + 1).collect(); if items.len() == per_page + 1 { items.pop(); next = Some(2); } } } SearchPage { items, next, prev, term, } } }