pub fn generate_pages(current: u32, total: u32, siblings: u32) -> Vec<u32> {
if total == 0 {
return Vec::new();
}
if total == 1 {
return vec![1];
}
let current = current.clamp(1, total);
let siblings = siblings.min(total.saturating_sub(1));
let start = if current > siblings.saturating_add(2) {
current.saturating_sub(siblings)
} else {
2
};
let end = if current.saturating_add(siblings) < total.saturating_sub(1) {
current.saturating_add(siblings)
} else {
total.saturating_sub(1)
};
let mut pages: Vec<u32> = Vec::new();
pages.push(1);
if start > 3 {
pages.push(0);
}
if end >= start {
for page in start..=end {
pages.push(page);
}
}
if end < total.saturating_sub(2) {
pages.push(0);
}
pages.push(total);
let mut result: Vec<u32> = Vec::with_capacity(pages.len());
for p in pages {
if result.last().copied() != Some(p) {
result.push(p);
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn generate_pages_single_page() {
let pages = generate_pages(1, 1, 1);
assert_eq!(pages, vec![1]);
}
#[test]
fn generate_pages_two_pages() {
let pages = generate_pages(1, 2, 1);
assert_eq!(pages, vec![1, 2]);
}
#[test]
fn generate_pages_first_page() {
let pages = generate_pages(1, 10, 1);
assert_eq!(pages, vec![1, 2, 0, 10]);
}
#[test]
fn generate_pages_last_page() {
let pages = generate_pages(10, 10, 1);
assert_eq!(pages, vec![1, 0, 9, 10]);
}
#[test]
fn generate_pages_middle_page() {
let pages = generate_pages(5, 10, 1);
assert!(!pages.is_empty());
assert!(pages.contains(&5));
assert_eq!(pages, vec![1, 0, 4, 5, 6, 0, 10]);
}
#[test]
fn generate_pages_with_ellipsis() {
let pages = generate_pages(5, 10, 1);
assert!(!pages.is_empty());
assert!(pages.contains(&0));
}
#[test]
fn generate_pages_many_siblings() {
let pages = generate_pages(5, 20, 3);
assert!(!pages.is_empty());
assert_eq!(pages, vec![1, 2, 3, 4, 5, 6, 7, 8, 0, 20]);
}
#[test]
fn generate_pages_edge_case_first() {
let pages = generate_pages(2, 10, 1);
assert!(pages.contains(&1));
assert!(pages.contains(&2));
assert_eq!(pages, vec![1, 2, 3, 0, 10]);
}
#[test]
fn generate_pages_edge_case_last() {
let pages = generate_pages(9, 10, 1);
assert!(pages.contains(&9));
assert!(pages.contains(&10));
assert_eq!(pages, vec![1, 0, 8, 9, 10]);
}
#[test]
fn generate_pages_all_visible() {
let pages = generate_pages(2, 3, 1);
assert_eq!(pages, vec![1, 2, 3]);
}
#[test]
fn generate_pages_current_equals_total() {
let pages = generate_pages(10, 10, 2);
assert!(pages.contains(&10));
assert_eq!(pages, vec![1, 0, 8, 9, 10]);
}
#[test]
fn generate_pages_siblings_zero() {
let pages = generate_pages(5, 10, 0);
assert_eq!(pages, vec![1, 0, 5, 0, 10]);
}
#[test]
fn generate_pages_no_ellipsis_after_first() {
let pages = generate_pages(2, 10, 1);
assert_eq!(pages, vec![1, 2, 3, 0, 10]);
}
#[test]
fn generate_pages_no_ellipsis_before_last() {
let pages = generate_pages(9, 10, 1);
assert_eq!(pages, vec![1, 0, 8, 9, 10]);
}
#[test]
fn generate_pages_both_ellipsis() {
let pages = generate_pages(4, 10, 1);
assert_eq!(pages, vec![1, 3, 4, 5, 0, 10]);
}
#[test]
fn generate_pages_no_ellipsis_when_total_small() {
let pages = generate_pages(2, 4, 1);
assert_eq!(pages, vec![1, 2, 3, 4]);
}
#[test]
fn generate_pages_show_all_when_siblings_large() {
let pages = generate_pages(3, 5, 10);
assert_eq!(pages, vec![1, 2, 3, 4, 5]);
}
#[test]
fn generate_pages_total_zero_returns_empty() {
assert!(generate_pages(1, 0, 0).is_empty());
assert!(generate_pages(5, 0, 3).is_empty());
}
#[test]
fn generate_pages_current_above_total_is_clamped() {
let pages = generate_pages(99, 10, 1);
assert_eq!(pages, vec![1, 0, 9, 10]);
}
#[test]
fn generate_pages_current_zero_is_clamped() {
let pages = generate_pages(0, 10, 1);
assert_eq!(pages, vec![1, 2, 0, 10]);
}
#[test]
fn generate_pages_siblings_max_does_not_overflow() {
let pages = generate_pages(5, 10, u32::MAX);
assert!(pages.first() == Some(&1));
assert!(pages.last() == Some(&10));
assert_eq!(pages, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
}
}