use std::collections::HashSet;
pub struct CompletePagedCollection<Row> {
pub rows: Vec<Row>,
pub page_count: u32,
pub last_cursor: Option<String>,
}
pub struct PagedCollectionPage {
page_len: usize,
new_rows: usize,
pub last_cursor_text: Option<String>,
}
pub struct PagedCollectionState<Row, Cursor> {
rows: Vec<Row>,
seen_row_ids: HashSet<String>,
page_count: u32,
next_cursor: Option<Cursor>,
}
impl<Row, Cursor> Default for PagedCollectionState<Row, Cursor> {
fn default() -> Self {
Self {
rows: Vec::new(),
seen_row_ids: HashSet::new(),
page_count: 0,
next_cursor: None,
}
}
}
impl<Row, Cursor> PagedCollectionState<Row, Cursor> {
pub fn new() -> Self {
Self::default()
}
pub const fn page_count(&self) -> u32 {
self.page_count
}
pub const fn row_count(&self) -> usize {
self.rows.len()
}
pub const fn next_cursor(&self) -> Option<&Cursor> {
self.next_cursor.as_ref()
}
pub const fn has_next_cursor(&self) -> bool {
self.next_cursor.is_some()
}
pub fn ingest_page(
&mut self,
rows: Vec<Row>,
next_cursor: Option<Cursor>,
cursor_text: impl FnOnce(&Cursor) -> String,
row_id: impl Fn(&Row) -> String,
) -> PagedCollectionPage {
self.page_count = self.page_count.saturating_add(1);
let page_len = rows.len();
let last_cursor_text = next_cursor.as_ref().map(cursor_text);
let mut new_rows = 0_usize;
for row in rows {
if self.seen_row_ids.insert(row_id(&row)) {
new_rows = new_rows.saturating_add(1);
self.rows.push(row);
}
}
self.next_cursor = next_cursor;
PagedCollectionPage {
page_len,
new_rows,
last_cursor_text,
}
}
pub fn into_complete(
self,
cursor_text: impl FnOnce(&Cursor) -> String,
) -> CompletePagedCollection<Row> {
CompletePagedCollection {
rows: self.rows,
page_count: self.page_count,
last_cursor: self.next_cursor.as_ref().map(cursor_text),
}
}
}
impl PagedCollectionPage {
pub fn exhausts_collection(&self, page_size: u32, has_next_cursor: bool) -> bool {
self.page_len < usize::try_from(page_size).unwrap_or(usize::MAX)
|| !has_next_cursor
|| self.new_rows == 0
}
}