canic/ops/model/memory/directory/
mod.rs1mod app;
2mod subnet;
3
4pub use app::*;
5pub use subnet::*;
6
7pub use crate::model::memory::directory::DirectoryView;
8
9use candid::CandidType;
10use serde::{Deserialize, Serialize};
11
12#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
17pub struct DirectoryPageDto {
18 pub entries: DirectoryView,
19 pub total: u64,
20 pub offset: u64,
21 pub limit: u64,
22}
23
24#[must_use]
29pub(crate) fn paginate(view: DirectoryView, offset: u64, limit: u64) -> DirectoryPageDto {
30 let total = view.len() as u64;
31 let (start, end) = pagination_bounds(total, offset, limit);
32
33 let entries = view.into_iter().skip(start).take(end - start).collect();
34
35 DirectoryPageDto {
36 entries,
37 total,
38 offset,
39 limit,
40 }
41}
42
43#[allow(clippy::cast_possible_truncation)]
44fn pagination_bounds(total: u64, offset: u64, limit: u64) -> (usize, usize) {
45 let start = offset.min(total);
46 let end = (offset + limit).min(total);
47
48 let start = start as usize;
49 let end = end as usize;
50
51 (start, end)
52}
53
54#[cfg(test)]
59mod tests {
60 use super::{DirectoryView, paginate};
61 use crate::{
62 model::memory::directory::PrincipalList,
63 types::{CanisterType, Principal},
64 };
65
66 fn p(id: u8) -> Principal {
67 Principal::from_slice(&[id; 29])
68 }
69
70 fn sample_view() -> DirectoryView {
71 vec![
72 ("a".into(), PrincipalList(vec![p(1)])),
73 ("b".into(), PrincipalList(vec![p(2), p(3)])),
74 ("c".into(), PrincipalList(vec![p(4)])),
75 ]
76 }
77
78 #[test]
79 fn paginate_within_bounds() {
80 let page = paginate(sample_view(), 1, 1);
81
82 assert_eq!(page.total, 3);
83 assert_eq!(page.offset, 1);
84 assert_eq!(page.limit, 1);
85 assert_eq!(page.entries.len(), 1);
86 assert_eq!(page.entries[0].0, CanisterType::from("b"));
87 }
88
89 #[test]
90 fn paginate_truncates_at_total() {
91 let page = paginate(sample_view(), 2, 5);
92
93 assert_eq!(page.total, 3);
94 assert_eq!(page.entries.len(), 1);
95 assert_eq!(page.entries[0].0, CanisterType::from("c"));
96 }
97
98 #[test]
99 fn paginate_handles_offset_beyond_range() {
100 let page = paginate(sample_view(), 10, 5);
101
102 assert_eq!(page.total, 3);
103 assert!(page.entries.is_empty());
104 assert_eq!(page.offset, 10);
105 assert_eq!(page.limit, 5);
106 }
107}