use std::cmp::Ordering;
#[derive(candid::CandidType, candid::Deserialize, Debug)]
pub struct Page {
pub page: u32, pub size: u32, }
#[derive(candid::CandidType, candid::Deserialize, Debug)]
pub struct PageData<T> {
pub page: u32, pub size: u32, pub total: u32, pub data: Vec<T>, }
impl<T: Clone> From<PageData<&T>> for PageData<T> {
fn from(value: PageData<&T>) -> Self {
PageData {
page: value.page,
size: value.size,
total: value.total,
data: value.data.into_iter().map(|t| t.clone()).collect(),
}
}
}
impl Page {
pub fn none<T>(&self) -> PageData<T> {
PageData {
page: self.page,
size: self.size,
total: 0,
data: Vec::new(),
}
}
}
pub fn page_check(page: &Page, max: u32) {
if page.page == 0 {
panic!("page can not be 0")
}
if max < page.size {
panic!("max page size is {} < {:?}", max, page.size)
}
}
pub fn page_find<T: Clone>(list: &Vec<T>, page: &Page, max: u32) -> PageData<T> {
page_check(&page, max);
let mut data = Vec::new();
let start = ((page.page - 1) * page.size) as usize;
let end = ((page.page) * page.size) as usize;
if end < list.len() {
data = (&list[start..end]).iter().map(|t| t.clone()).collect();
} else if start < list.len() {
data = (&list[start..]).iter().map(|t| t.clone()).collect();
}
PageData {
page: page.page,
size: page.size,
total: list.len() as u32,
data,
}
}
pub fn page_find_with_reserve<'a, T>(list: &'a Vec<T>, page: &Page, max: u32) -> PageData<&'a T> {
page_check(&page, max);
if list.len() == 0 {
return page.none();
}
let mut index_list: Vec<usize> = (0..list.len()).into_iter().collect();
index_list.reverse(); let mut data = Vec::new();
let start = ((page.page - 1) * page.size) as usize;
let end = ((page.page) * page.size) as usize;
if end < index_list.len() {
data = (&index_list[start..end])
.iter()
.map(|i| &list[*i]) .collect();
} else if start < index_list.len() {
data = (&index_list[start..])
.iter()
.map(|i| &list[*i]) .collect();
}
PageData {
page: page.page,
size: page.size,
total: list.len() as u32,
data,
}
}
pub fn page_find_with_reserve_and_filter<'a, T, F>(
list: &'a Vec<T>,
page: &Page,
max: u32,
filter: F, ) -> PageData<&'a T>
where
F: Fn(&T) -> bool,
{
page_check(&page, max);
if list.len() == 0 {
return page.none();
}
let mut index_list: Vec<usize> = (0..list.len())
.into_iter()
.filter(|i| filter(&list[*i]))
.collect();
index_list.reverse(); let mut data = Vec::new();
let start = ((page.page - 1) * page.size) as usize;
let end = ((page.page) * page.size) as usize;
if end < index_list.len() {
data = (&index_list[start..end])
.iter()
.map(|i| &list[*i]) .collect();
} else if start < index_list.len() {
data = (&index_list[start..])
.iter()
.map(|i| &list[*i]) .collect();
}
PageData {
page: page.page,
size: page.size,
total: index_list.len() as u32,
data,
}
}
pub fn page_find_with_sort<T, F, C, S, R>(
list: &Vec<T>,
page: &Page,
max: u32,
filter: F, compare: C, transform: S, ) -> PageData<R>
where
F: Fn(&T) -> bool,
C: Fn(&T, &T) -> Ordering,
S: Fn(&T) -> R,
{
page_check(&page, max);
let mut list: Vec<&T> = list.iter().filter(|item| filter(item)).collect();
list.sort_by(|a, b| compare(a, b));
let mut data = Vec::new();
let start = ((page.page - 1) * page.size) as usize;
let end = ((page.page) * page.size) as usize;
if end < list.len() {
data = (&list[start..end]).iter().map(|t| transform(t)).collect();
} else if start < list.len() {
data = (&list[start..]).iter().map(|t| transform(t)).collect();
}
PageData {
page: page.page,
size: page.size,
total: list.len() as u32,
data,
}
}