use std::time::Duration;
#[derive(Clone, Debug)]
pub(crate) struct ErasePlan(pub Vec<(u8, usize, u32, Option<Duration>)>);
impl ErasePlan {
pub fn new(insts: &[(usize, u8, Option<Duration>)], start: usize, length: usize) -> Self {
log::trace!("Creating erase plan, start={} length={}", start, length);
let mut plan = Vec::new();
let mut insts = insts.to_vec();
insts.sort();
let end = start + length;
let mut pos = start;
while pos < end {
log::trace!("Evaluating candidates, pos={} end={}", pos, end);
let mut candidate = (0, usize::MAX, 0, 0, None);
for (erase_size, opcode, duration) in insts.iter() {
let erase_base = pos - (pos % erase_size);
let erase_end = erase_base + erase_size - 1;
let mut bytes = erase_size - (pos - erase_base);
if erase_end > end {
bytes -= erase_end - end + 1;
}
log::trace!(" Candidate 0x{:02X} ({} bytes): base={} end={} bytes={}",
opcode, erase_size, erase_base, erase_end, bytes);
if bytes > candidate.0 || (bytes == candidate.0 && *erase_size < candidate.1) {
candidate = (bytes, *erase_size, *opcode, erase_base, *duration);
}
}
log::trace!("Candidate selected: {:?}", candidate);
pos += candidate.0;
plan.push((candidate.2, candidate.1, candidate.3 as u32, candidate.4));
}
log::debug!("Erase plan: {:?}", plan);
ErasePlan(plan)
}
pub fn total_size(&self) -> usize {
self.0.iter().map(|x| x.1).sum()
}
}
#[test]
fn test_erase_plan() {
let insts = &[(4, 1, None), (32, 2, None), (64, 3, None)];
assert_eq!(ErasePlan::new(insts, 0, 4).0,
vec![(1, 4, 0, None)]);
assert_eq!(ErasePlan::new(insts, 0, 64).0,
vec![(3, 64, 0, None)]);
assert_eq!(ErasePlan::new(insts, 0, 192).0,
vec![(3, 64, 0, None), (3, 64, 64, None), (3, 64, 128, None)]);
assert_eq!(ErasePlan::new(insts, 0, 70).0,
vec![(3, 64, 0, None), (2, 32, 64, None)]);
assert_eq!(ErasePlan::new(insts, 0, 66).0,
vec![(3, 64, 0, None), (1, 4, 64, None)]);
assert_eq!(ErasePlan::new(insts, 62, 64).0,
vec![(1, 4, 60, None), (3, 64, 64, None)]);
assert_eq!(ErasePlan::new(insts, 62, 68).0,
vec![(1, 4, 60, None), (3, 64, 64, None), (1, 4, 128, None)]);
}