use crate::msf::PageNumber;
use crate::source::SourceSlice;
#[derive(Debug)]
pub struct PageList {
page_size: usize,
source_slices: Vec<SourceSlice>,
last_page: Option<PageNumber>,
truncated: bool,
}
impl PageList {
pub fn new(page_size: usize) -> Self {
PageList {
page_size,
source_slices: Vec::new(),
last_page: None,
truncated: false,
}
}
pub fn push(&mut self, page: PageNumber) {
assert!(!self.truncated);
let is_continuous = match self.last_page {
Some(n) => (n + 1) == page,
None => false,
};
if is_continuous {
debug_assert!(!self.source_slices.is_empty());
let last_slice = self.source_slices.last_mut().unwrap();
last_slice.size += self.page_size;
} else {
self.source_slices.push(SourceSlice {
offset: (self.page_size as u64) * u64::from(page),
size: self.page_size,
});
}
self.last_page = Some(page);
}
pub fn truncate(&mut self, bytes: usize) {
let mut bytes = bytes;
let mut new_slices: Vec<SourceSlice> = Vec::new();
for slice in &self.source_slices {
let mut slice: SourceSlice = *slice;
if bytes > 0 {
if slice.size > bytes {
slice.size = bytes;
}
new_slices.push(slice);
bytes -= slice.size;
} else {
break;
}
}
self.source_slices = new_slices;
self.truncated = true;
}
pub fn len(&self) -> usize {
self.source_slices
.iter()
.fold(0 as usize, |acc, s| acc + s.size)
}
pub fn source_slices(&self) -> &[SourceSlice] {
self.source_slices.as_slice()
}
}
#[cfg(test)]
mod tests {
use crate::msf::page_list::*;
use crate::source::SourceSlice;
#[test]
fn test_push() {
let mut list = PageList::new(4096);
list.push(0);
list.push(1);
let expected = vec![SourceSlice {
offset: 0,
size: 8192,
}];
assert_eq!(list.source_slices(), expected.as_slice());
assert_eq!(list.len(), 8192);
list.push(4);
list.push(5);
let expected = vec![
SourceSlice {
offset: 0,
size: 8192,
},
SourceSlice {
offset: 16384,
size: 8192,
},
];
assert_eq!(list.source_slices(), expected.as_slice());
assert_eq!(list.len(), 16384);
list.push(2);
let expected = vec![
SourceSlice {
offset: 0,
size: 8192,
},
SourceSlice {
offset: 16384,
size: 8192,
},
SourceSlice {
offset: 8192,
size: 4096,
},
];
assert_eq!(list.source_slices(), expected.as_slice());
assert_eq!(list.len(), 20480);
list.push(2);
let expected = vec![
SourceSlice {
offset: 0,
size: 8192,
},
SourceSlice {
offset: 16384,
size: 8192,
},
SourceSlice {
offset: 8192,
size: 4096,
},
SourceSlice {
offset: 8192,
size: 4096,
},
];
assert_eq!(list.source_slices(), expected.as_slice());
assert_eq!(list.len(), 24576);
}
#[test]
fn test_truncate() {
let mut list = PageList::new(4096);
list.push(0);
list.push(1);
list.push(4);
list.push(5);
list.push(2);
list.push(2);
assert_eq!(list.len(), 24576);
list.truncate(25000);
let expected = vec![
SourceSlice {
offset: 0,
size: 8192,
},
SourceSlice {
offset: 16384,
size: 8192,
},
SourceSlice {
offset: 8192,
size: 4096,
},
SourceSlice {
offset: 8192,
size: 4096,
},
];
assert_eq!(list.source_slices(), expected.as_slice());
assert_eq!(list.len(), 24576);
list.truncate(24000);
let expected = vec![
SourceSlice {
offset: 0,
size: 8192,
},
SourceSlice {
offset: 16384,
size: 8192,
},
SourceSlice {
offset: 8192,
size: 4096,
},
SourceSlice {
offset: 8192,
size: 3520,
},
];
assert_eq!(list.source_slices(), expected.as_slice());
assert_eq!(list.len(), 24000);
list.truncate(10000);
let expected = vec![
SourceSlice {
offset: 0,
size: 8192,
},
SourceSlice {
offset: 16384,
size: 1808,
},
];
assert_eq!(list.source_slices(), expected.as_slice());
assert_eq!(list.len(), 10000);
list.truncate(12000);
let expected = vec![
SourceSlice {
offset: 0,
size: 8192,
},
SourceSlice {
offset: 16384,
size: 1808,
},
];
assert_eq!(list.source_slices(), expected.as_slice());
assert_eq!(list.len(), 10000);
list.truncate(0);
assert_eq!(list.source_slices().len(), 0);
assert_eq!(list.len(), 0);
}
#[test]
#[should_panic]
fn test_push_after_truncate() {
let mut list = PageList::new(4096);
list.push(5);
list.truncate(2000);
list.push(6);
}
}