#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Cursor(u32);
impl Cursor {
#[must_use]
pub const fn at(position: u32) -> Self {
Self(position)
}
#[must_use]
pub const fn position(self) -> u32 {
self.0
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Page<T> {
items: Vec<T>,
next: Option<Cursor>,
}
impl<T> Page<T> {
#[must_use]
pub const fn complete(items: Vec<T>) -> Self {
Self { items, next: None }
}
#[must_use]
pub const fn partial(items: Vec<T>, next: Cursor) -> Self {
Self {
items,
next: Some(next),
}
}
#[must_use]
pub fn items(&self) -> &[T] {
&self.items
}
#[must_use]
pub const fn next_cursor(&self) -> Option<Cursor> {
self.next
}
#[must_use]
pub const fn has_more(&self) -> bool {
self.next.is_some()
}
#[must_use]
pub fn len(&self) -> usize {
self.items.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
#[must_use]
pub fn into_items(self) -> Vec<T> {
self.items
}
}
impl<T> IntoIterator for Page<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.items.into_iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn complete_page_has_no_cursor() {
let page = Page::complete(vec![1, 2, 3]);
assert_eq!(page.len(), 3);
assert!(!page.has_more());
assert!(page.next_cursor().is_none());
}
#[test]
fn partial_page_carries_a_cursor() {
let page = Page::partial(vec![1], Cursor::at(4));
assert!(page.has_more());
assert_eq!(page.next_cursor().unwrap().position(), 4);
}
#[test]
fn empty_complete_page_is_exhausted_not_truncated() {
let page: Page<u8> = Page::complete(vec![]);
assert!(page.is_empty());
assert!(!page.has_more());
}
#[test]
fn empty_partial_page_still_reports_more() {
let page: Page<u8> = Page::partial(vec![], Cursor::at(1));
assert!(page.is_empty());
assert!(page.has_more());
}
#[test]
fn into_items_returns_the_results() {
let page = Page::complete(vec![7, 8]);
assert_eq!(page.into_items(), vec![7, 8]);
}
#[test]
fn page_iterates() {
let page = Page::complete(vec![1, 2, 3]);
assert_eq!(page.into_iter().sum::<i32>(), 6);
}
}