1use alloc::vec::Vec;
2use core::time::Duration;
3
4#[derive(Clone, Debug)]
6pub(crate) struct ErasePlan(pub Vec<(u8, usize, u32, Option<Duration>)>);
7
8impl ErasePlan {
9 pub fn new(insts: &[(usize, u8, Option<Duration>)], start: usize, length: usize) -> Self {
10 log::trace!("Creating erase plan, start={} length={}", start, length);
11 let mut plan = Vec::new();
12
13 let mut insts = insts.to_vec();
15 insts.sort();
16
17 let end = start + length;
21 let mut pos = start;
22 while pos < end {
23 log::trace!("Evaluating candidates, pos={} end={}", pos, end);
24 let mut candidate = (0, usize::MAX, 0, 0, None);
26 for (erase_size, opcode, duration) in insts.iter() {
27 let erase_base = pos - (pos % erase_size);
28 let erase_end = erase_base + erase_size - 1;
29 let mut bytes = erase_size - (pos - erase_base);
30 if erase_end > end {
31 bytes -= erase_end - end + 1;
32 }
33 log::trace!(
34 " Candidate 0x{:02X} ({} bytes): base={} end={} bytes={}",
35 opcode,
36 erase_size,
37 erase_base,
38 erase_end,
39 bytes
40 );
41 if bytes > candidate.0 || (bytes == candidate.0 && *erase_size < candidate.1) {
42 candidate = (bytes, *erase_size, *opcode, erase_base, *duration);
43 }
44 }
45
46 log::trace!("Candidate selected: {:?}", candidate);
47 pos += candidate.0;
48 plan.push((candidate.2, candidate.1, candidate.3 as u32, candidate.4));
49 }
50
51 log::debug!("Erase plan: {:?}", plan);
52
53 ErasePlan(plan)
54 }
55
56 #[cfg(feature = "std")]
57 pub fn total_size(&self) -> usize {
58 self.0.iter().map(|x| x.1).sum()
59 }
60}
61
62#[test]
63fn test_erase_plan() {
64 let insts = &[(4, 1, None), (32, 2, None), (64, 3, None)];
65 assert_eq!(ErasePlan::new(insts, 0, 4).0, alloc::vec![(1, 4, 0, None)]);
67 assert_eq!(
69 ErasePlan::new(insts, 0, 64).0,
70 alloc::vec![(3, 64, 0, None)]
71 );
72 assert_eq!(
74 ErasePlan::new(insts, 0, 192).0,
75 alloc::vec![(3, 64, 0, None), (3, 64, 64, None), (3, 64, 128, None)]
76 );
77 assert_eq!(
79 ErasePlan::new(insts, 0, 70).0,
80 alloc::vec![(3, 64, 0, None), (2, 32, 64, None)]
81 );
82 assert_eq!(
84 ErasePlan::new(insts, 0, 66).0,
85 alloc::vec![(3, 64, 0, None), (1, 4, 64, None)]
86 );
87 assert_eq!(
89 ErasePlan::new(insts, 62, 64).0,
90 alloc::vec![(1, 4, 60, None), (3, 64, 64, None)]
91 );
92 assert_eq!(
94 ErasePlan::new(insts, 62, 68).0,
95 alloc::vec![(1, 4, 60, None), (3, 64, 64, None), (1, 4, 128, None)]
96 );
97}