1use spacepackets::cfdp::{LargeFileFlag, pdu::nak::NakPduCreatorWithReservedSeqReqsBuf};
14
15#[derive(Debug, PartialEq, Eq, thiserror::Error)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18#[non_exhaustive]
19pub enum LostSegmentError {
20 #[error("store is full")]
21 StoreFull,
22 #[error("segment is empty")]
23 EmptySegment,
24 #[error("segment start {0} is larger than segment end {1}")]
25 StartLargerThanEnd(u64, u64),
26 #[error("large file segments are not supported")]
27 LargeFileSegmentNotSupported,
28 #[error("invalid segment boundary detected for lost segment ({0}, {1})")]
29 InvalidSegmentBoundary(u64, u64),
30}
31
32#[derive(Debug, PartialEq, Eq, thiserror::Error)]
33#[cfg_attr(feature = "defmt", derive(defmt::Format))]
34#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35#[non_exhaustive]
36pub enum LostSegmentWriteError {
37 #[error("number of segments mismatch: expected {expected}, actual {actual}")]
38 NumberOfSegmentsMismatch { expected: usize, actual: usize },
39 #[error("buffer size not equal to required size")]
40 BufferSizeMissmatch { expected: usize, actual: usize },
41 #[error("large file segment not compatible to normal file size")]
42 LargeSegmentForNormalFileSize,
43}
44
45pub trait LostSegmentStore {
50 type Iter<'a>: Iterator<Item = (u64, u64)> + 'a
52 where
53 Self: 'a;
54
55 fn iter(&self) -> Self::Iter<'_>;
57
58 fn number_of_segments(&self) -> usize;
60
61 fn supports_large_file_size(&self) -> bool;
64 fn capacity(&self) -> Option<usize>;
65 fn reset(&mut self);
66
67 fn segment_in_store(&self, segment: (u64, u64)) -> bool;
72
73 fn add_lost_segment(&mut self, lost_seg: (u64, u64)) -> Result<(), LostSegmentError>;
80
81 fn remove_lost_segment(
89 &mut self,
90 segment_to_remove: (u64, u64),
91 ) -> Result<bool, LostSegmentError>;
92
93 fn coalesce_lost_segments(&mut self) -> Result<(), LostSegmentError>;
96
97 #[inline]
98 fn is_empty(&self) -> bool {
99 self.number_of_segments() == 0
100 }
101
102 fn write_segments_to_bytes(
105 &self,
106 buf: &mut [u8],
107 file_flag: LargeFileFlag,
108 ) -> Result<usize, LostSegmentWriteError> {
109 let len_per_segment = if file_flag == LargeFileFlag::Large {
110 16
111 } else {
112 8
113 };
114 let written_len = self.number_of_segments() * len_per_segment;
115 if written_len != buf.len() {
116 return Err(LostSegmentWriteError::BufferSizeMissmatch {
117 expected: written_len,
118 actual: buf.len(),
119 });
120 }
121 let mut current_index = 0;
122 for segment in self.iter() {
123 match file_flag {
124 LargeFileFlag::Normal => {
125 if segment.0 > u32::MAX as u64 || segment.1 > u32::MAX as u64 {
126 return Err(LostSegmentWriteError::LargeSegmentForNormalFileSize);
127 }
128 buf[current_index..current_index + 4]
129 .copy_from_slice(&(segment.0 as u32).to_be_bytes());
130 current_index += 4;
131 buf[current_index..current_index + 4]
132 .copy_from_slice(&(segment.1 as u32).to_be_bytes());
133 current_index += 4;
134 }
135 LargeFileFlag::Large => {
136 buf[current_index..current_index + 8]
137 .copy_from_slice(&(segment.0).to_be_bytes());
138 current_index += 8;
139 buf[current_index..current_index + 8]
140 .copy_from_slice(&(segment.1).to_be_bytes());
141 current_index += 8;
142 }
143 }
144 }
145 Ok(current_index)
146 }
147
148 fn write_to_nak_segment_list(
155 &self,
156 nak_builder: &mut NakPduCreatorWithReservedSeqReqsBuf,
157 first_segment_request_for_metadata: bool,
158 ) -> Result<usize, LostSegmentWriteError> {
159 let file_flag = nak_builder.pdu_header().common_pdu_conf().file_flag;
160 let mut relevant_size = self.number_of_segments();
161 if first_segment_request_for_metadata {
162 relevant_size += 1;
163 }
164 if nak_builder.num_segment_reqs() != relevant_size {
165 return Err(LostSegmentWriteError::NumberOfSegmentsMismatch {
166 expected: self.number_of_segments(),
167 actual: nak_builder.num_segment_reqs(),
168 });
169 }
170 let mut buf = nak_builder.segment_request_buffer_mut();
171 let mut written_len = 0;
172 if first_segment_request_for_metadata {
173 match file_flag {
174 LargeFileFlag::Normal => {
175 buf[0..8].fill(0);
176 buf = &mut buf[8..];
177 written_len += 8;
178 }
179 LargeFileFlag::Large => {
180 buf[0..16].fill(0);
181 buf = &mut buf[16..];
182 written_len += 16;
183 }
184 }
185 }
186 written_len += self.write_segments_to_bytes(buf, file_flag)?;
187 Ok(written_len)
188 }
189}
190
191#[cfg(feature = "alloc")]
196#[derive(Debug, Default)]
197pub struct LostSegmentsList {
198 list: alloc::vec::Vec<(u64, u64)>,
199 opt_capacity: Option<usize>,
200}
201
202#[cfg(feature = "alloc")]
203impl LostSegmentsList {
204 pub fn new(opt_capacity: Option<usize>) -> Self {
205 Self {
206 list: alloc::vec::Vec::new(),
207 opt_capacity,
208 }
209 }
210}
211
212#[cfg(feature = "alloc")]
213impl LostSegmentStore for LostSegmentsList {
214 type Iter<'a>
215 = core::iter::Cloned<core::slice::Iter<'a, (u64, u64)>>
216 where
217 Self: 'a;
218
219 fn iter(&self) -> Self::Iter<'_> {
220 self.list.iter().cloned()
221 }
222
223 #[inline]
224 fn number_of_segments(&self) -> usize {
225 self.list.len()
226 }
227
228 #[inline]
229 fn supports_large_file_size(&self) -> bool {
230 true
231 }
232
233 #[inline]
234 fn capacity(&self) -> Option<usize> {
235 self.opt_capacity
236 }
237
238 #[inline]
239 fn reset(&mut self) {
240 self.list.clear();
241 }
242
243 fn segment_in_store(&self, segment: (u64, u64)) -> bool {
244 for (seg_start, seg_end) in &self.list {
245 if segment.0 >= *seg_start && segment.1 <= *seg_end {
246 return true;
247 }
248 }
249 false
250 }
251
252 #[inline]
253 fn add_lost_segment(&mut self, lost_seg: (u64, u64)) -> Result<(), LostSegmentError> {
254 if lost_seg.1 == lost_seg.0 {
255 return Err(LostSegmentError::EmptySegment);
256 }
257 if lost_seg.0 > lost_seg.1 {
258 return Err(LostSegmentError::StartLargerThanEnd(lost_seg.0, lost_seg.1));
259 }
260 if let Some(capacity) = self.opt_capacity {
261 if self.list.len() == capacity {
262 return Err(LostSegmentError::StoreFull);
263 }
264 }
265 self.list.push((lost_seg.0, lost_seg.1));
266 Ok(())
267 }
268
269 fn coalesce_lost_segments(&mut self) -> Result<(), LostSegmentError> {
270 self.list.retain(|&(s, e)| e > s);
272 if self.list.len() <= 1 {
273 return Ok(());
274 }
275
276 self.list
278 .as_mut_slice()
279 .sort_unstable_by_key(|&(start, _)| start);
280
281 let mut w = 0usize;
283 for i in 0..self.list.len() {
284 if w == 0 {
285 self.list[w] = self.list[i];
286 w = 1;
287 continue;
288 }
289
290 let (prev_s, mut prev_e) = self.list[w - 1];
291 let (s, e) = self.list[i];
292
293 if s <= prev_e {
294 if e > prev_e {
296 prev_e = e;
297 self.list[w - 1] = (prev_s, prev_e);
298 }
299 } else {
300 self.list[w] = (s, e);
302 w += 1;
303 }
304 }
305
306 self.list.truncate(w);
308 Ok(())
309 }
310
311 #[inline]
312 fn remove_lost_segment(
313 &mut self,
314 segment_to_remove: (u64, u64),
315 ) -> Result<bool, LostSegmentError> {
316 if segment_to_remove.1 == segment_to_remove.0 {
317 return Err(LostSegmentError::EmptySegment);
318 }
319 if segment_to_remove.0 > segment_to_remove.1 {
320 return Err(LostSegmentError::StartLargerThanEnd(
321 segment_to_remove.0,
322 segment_to_remove.1,
323 ));
324 }
325
326 let idx = match self
328 .list
329 .binary_search_by_key(&segment_to_remove.0, |&(s, _)| s)
330 {
331 Ok(idx) => idx,
332 Err(insertion) => insertion.saturating_sub(1),
333 };
334
335 let mut i = idx;
337 let list_len = self.list.len();
338 while i < self.list.len() && self.list[i].0 <= segment_to_remove.1 {
339 let seg = &mut self.list[i];
340
341 if seg.1 < segment_to_remove.0 {
343 i += 1;
344 continue;
345 }
346
347 if seg == &segment_to_remove {
349 self.list.remove(i);
350 return Ok(true);
352 }
353
354 if (segment_to_remove.0 < seg.0 && segment_to_remove.1 > seg.0)
356 || (segment_to_remove.1 > seg.1 && segment_to_remove.0 < seg.1)
357 {
358 return Err(LostSegmentError::InvalidSegmentBoundary(
359 segment_to_remove.0,
360 segment_to_remove.1,
361 ));
362 }
363
364 let mut changed = false;
367
368 if segment_to_remove.1 == seg.1 {
370 seg.1 = segment_to_remove.0;
371 changed = true;
372 }
373 if segment_to_remove.0 == seg.0 {
375 seg.0 = segment_to_remove.1;
376 changed = true;
377 }
378 if segment_to_remove.0 > seg.0 && segment_to_remove.1 < seg.1 {
380 if list_len == self.opt_capacity.unwrap_or(usize::MAX) {
381 return Err(LostSegmentError::StoreFull);
382 }
383 let end_of_right_remainder = seg.1;
385 seg.1 = segment_to_remove.0;
387 self.list
388 .insert(i + 1, (segment_to_remove.1, end_of_right_remainder));
389 changed = true;
390 }
391
392 if changed {
394 return Ok(true);
395 }
396
397 i += 1;
398 }
399 Ok(false)
400 }
401}
402
403#[derive(Default, Debug)]
405pub struct LostSegmentsListHeapless<const N: usize, T> {
406 list: heapless::vec::Vec<(T, T), N>,
407}
408
409pub type LostSegmentsListNormalFilesHeapless<const N: usize> = LostSegmentsListHeapless<N, u32>;
412
413impl<const N: usize, T> LostSegmentsListHeapless<N, T> {
414 pub fn new() -> Self {
415 Self {
416 list: heapless::Vec::new(),
417 }
418 }
419
420 #[inline]
421 fn num_lost_segments(&self) -> usize {
422 self.list.len()
423 }
424
425 #[inline]
426 fn capacity(&self) -> Option<usize> {
427 Some(N)
428 }
429
430 #[inline]
431 fn reset(&mut self) {
432 self.list.clear();
433 }
434}
435
436impl<const N: usize, T: Copy + Clone + Ord> LostSegmentsListHeapless<N, T> {
437 fn coalesce_lost_segments(&mut self) -> Result<(), LostSegmentError> {
438 self.list.retain(|&(s, e)| e > s);
440 if self.list.len() <= 1 {
441 return Ok(());
442 }
443
444 self.list
446 .as_mut_slice()
447 .sort_unstable_by(|a, b| a.0.cmp(&b.0).then(a.1.cmp(&b.1)));
448
449 let mut w = 0usize;
451 for i in 0..self.list.len() {
452 if w == 0 {
453 self.list[w] = self.list[i];
454 w = 1;
455 continue;
456 }
457
458 let (prev_s, mut prev_e) = self.list[w - 1];
459 let (s, e) = self.list[i];
460
461 if s <= prev_e {
462 if e > prev_e {
464 prev_e = e;
465 self.list[w - 1] = (prev_s, prev_e);
466 }
467 } else {
468 self.list[w] = (s, e);
470 w += 1;
471 }
472 }
473
474 self.list.truncate(w);
476 Ok(())
477 }
478}
479
480impl<const N: usize> LostSegmentStore for LostSegmentsListHeapless<N, u64> {
481 type Iter<'a>
482 = core::iter::Cloned<core::slice::Iter<'a, (u64, u64)>>
483 where
484 Self: 'a;
485
486 fn iter(&self) -> Self::Iter<'_> {
487 self.list.iter().cloned()
488 }
489
490 fn add_lost_segment(&mut self, lost_seg: (u64, u64)) -> Result<(), LostSegmentError> {
491 if lost_seg.1 == lost_seg.0 {
492 return Err(LostSegmentError::EmptySegment);
493 }
494 if lost_seg.0 > lost_seg.1 {
495 return Err(LostSegmentError::StartLargerThanEnd(lost_seg.0, lost_seg.1));
496 }
497 if self.list.is_full() {
498 return Err(LostSegmentError::StoreFull);
499 }
500 self.list.push(lost_seg).ok();
501 Ok(())
502 }
503
504 fn remove_lost_segment(
505 &mut self,
506 segment_to_remove: (u64, u64),
507 ) -> Result<bool, LostSegmentError> {
508 if segment_to_remove.1 == segment_to_remove.0 {
509 return Err(LostSegmentError::EmptySegment);
510 }
511 if segment_to_remove.0 > segment_to_remove.1 {
512 return Err(LostSegmentError::StartLargerThanEnd(
513 segment_to_remove.0,
514 segment_to_remove.1,
515 ));
516 }
517
518 let idx = match self
520 .list
521 .binary_search_by_key(&segment_to_remove.0, |&(s, _)| s)
522 {
523 Ok(idx) => idx,
524 Err(insertion) => insertion.saturating_sub(1),
525 };
526
527 let mut i = idx;
529 let list_len = self.list.len();
530 while i < self.list.len() && self.list[i].0 <= segment_to_remove.1 {
531 let seg = &mut self.list[i];
532
533 if seg.1 < segment_to_remove.0 {
535 i += 1;
536 continue;
537 }
538
539 if seg == &segment_to_remove {
541 self.list.remove(i);
542 return Ok(true);
543 }
544
545 if (segment_to_remove.0 < seg.0 && segment_to_remove.1 > seg.0)
547 || (segment_to_remove.1 > seg.1 && segment_to_remove.0 < seg.1)
548 {
549 return Err(LostSegmentError::InvalidSegmentBoundary(
550 segment_to_remove.0,
551 segment_to_remove.1,
552 ));
553 }
554
555 let mut changed = false;
558
559 if segment_to_remove.1 == seg.1 {
561 seg.1 = segment_to_remove.0;
562 changed = true;
563 }
564 if segment_to_remove.0 == seg.0 {
566 seg.0 = segment_to_remove.1;
567 changed = true;
568 }
569 if segment_to_remove.0 > seg.0 && segment_to_remove.1 < seg.1 {
571 if list_len == N {
572 return Err(LostSegmentError::StoreFull);
573 }
574 let end_of_right_remainder = seg.1;
576 seg.1 = segment_to_remove.0;
578 self.list
579 .insert(i + 1, (segment_to_remove.1, end_of_right_remainder))
580 .unwrap();
581 changed = true;
582 }
583
584 if changed {
586 return Ok(true);
587 }
588
589 i += 1;
590 }
591 Ok(false)
592 }
593
594 fn coalesce_lost_segments(&mut self) -> Result<(), LostSegmentError> {
595 self.coalesce_lost_segments()
596 }
597
598 fn number_of_segments(&self) -> usize {
599 self.num_lost_segments()
600 }
601
602 fn supports_large_file_size(&self) -> bool {
603 true
604 }
605
606 fn capacity(&self) -> Option<usize> {
607 self.capacity()
608 }
609
610 fn reset(&mut self) {
611 self.reset();
612 }
613
614 fn segment_in_store(&self, segment: (u64, u64)) -> bool {
615 for (seg_start, seg_end) in &self.list {
616 if segment.0 >= *seg_start && segment.1 <= *seg_end {
617 return true;
618 }
619 }
620 false
621 }
622}
623
624impl<const N: usize> LostSegmentStore for LostSegmentsListHeapless<N, u32> {
625 type Iter<'a>
626 = core::iter::Map<core::slice::Iter<'a, (u32, u32)>, fn(&(u32, u32)) -> (u64, u64)>
627 where
628 Self: 'a;
629
630 fn iter(&self) -> Self::Iter<'_> {
631 self.list.iter().map(|pair| (pair.0 as u64, pair.1 as u64))
632 }
633
634 fn add_lost_segment(&mut self, lost_seg: (u64, u64)) -> Result<(), LostSegmentError> {
635 if lost_seg.1 == lost_seg.0 {
636 return Err(LostSegmentError::EmptySegment);
637 }
638 if lost_seg.0 > lost_seg.1 {
639 return Err(LostSegmentError::StartLargerThanEnd(lost_seg.0, lost_seg.1));
640 }
641 if lost_seg.1 > u32::MAX as u64 || lost_seg.0 > u32::MAX as u64 {
642 return Err(LostSegmentError::LargeFileSegmentNotSupported);
643 }
644 if self.list.is_full() {
645 return Err(LostSegmentError::StoreFull);
646 }
647 self.list.push((lost_seg.0 as u32, lost_seg.1 as u32)).ok();
648 Ok(())
649 }
650
651 fn remove_lost_segment(
652 &mut self,
653 segment_to_remove: (u64, u64),
654 ) -> Result<bool, LostSegmentError> {
655 if segment_to_remove.0 > u32::MAX as u64 || segment_to_remove.1 > u32::MAX as u64 {
656 return Err(LostSegmentError::LargeFileSegmentNotSupported);
657 }
658 if segment_to_remove.1 == segment_to_remove.0 {
659 return Err(LostSegmentError::EmptySegment);
660 }
661 if segment_to_remove.0 > segment_to_remove.1 {
662 return Err(LostSegmentError::StartLargerThanEnd(
663 segment_to_remove.0,
664 segment_to_remove.1,
665 ));
666 }
667
668 let idx = match self
670 .list
671 .binary_search_by_key(&segment_to_remove.0, |&(s, _)| s as u64)
672 {
673 Ok(idx) => idx,
674 Err(insertion) => insertion.saturating_sub(1),
675 };
676
677 let mut i = idx;
679 let list_len = self.list.len();
680 while i < self.list.len() && self.list[i].0 as u64 <= segment_to_remove.1 {
681 let seg = &mut self.list[i];
682
683 if (seg.1 as u64) < segment_to_remove.0 {
685 i += 1;
686 continue;
687 }
688
689 if seg.0 as u64 == segment_to_remove.0 && seg.1 as u64 == segment_to_remove.1 {
691 self.list.remove(i);
692 return Ok(true);
693 }
694
695 if (segment_to_remove.0 < seg.0 as u64 && segment_to_remove.1 > seg.0 as u64)
697 || (segment_to_remove.1 > seg.1 as u64 && segment_to_remove.0 < seg.1 as u64)
698 {
699 return Err(LostSegmentError::InvalidSegmentBoundary(
700 segment_to_remove.0,
701 segment_to_remove.1,
702 ));
703 }
704
705 let mut changed = false;
708
709 if segment_to_remove.1 == seg.1 as u64 {
711 seg.1 = segment_to_remove.0 as u32;
712 changed = true;
713 }
714 if segment_to_remove.0 == seg.0 as u64 {
716 seg.0 = segment_to_remove.1 as u32;
717 changed = true;
718 }
719 if segment_to_remove.0 > seg.0 as u64 && segment_to_remove.1 < seg.1 as u64 {
721 if list_len == N {
722 return Err(LostSegmentError::StoreFull);
723 }
724 let end_of_right_remainder = seg.1;
726 seg.1 = segment_to_remove.0 as u32;
728 self.list
729 .insert(i + 1, (segment_to_remove.1 as u32, end_of_right_remainder))
730 .unwrap();
731 changed = true;
732 }
733
734 if changed {
736 return Ok(true);
737 }
738
739 i += 1;
740 }
741 Ok(false)
742 }
743
744 fn coalesce_lost_segments(&mut self) -> Result<(), LostSegmentError> {
745 self.coalesce_lost_segments()
746 }
747
748 #[inline]
749 fn number_of_segments(&self) -> usize {
750 self.num_lost_segments()
751 }
752
753 #[inline]
754 fn supports_large_file_size(&self) -> bool {
755 false
756 }
757
758 #[inline]
759 fn capacity(&self) -> Option<usize> {
760 self.capacity()
761 }
762
763 #[inline]
764 fn reset(&mut self) {
765 self.reset();
766 }
767
768 fn segment_in_store(&self, segment: (u64, u64)) -> bool {
769 for (seg_start, seg_end) in &self.list {
770 if segment.0 >= *seg_start as u64 && segment.1 <= *seg_end as u64 {
771 return true;
772 }
773 }
774 false
775 }
776}
777
778#[cfg(test)]
779mod tests {
780 use std::vec::Vec;
781
782 use super::*;
783
784 fn generic_basic_state_test(
785 store: &impl LostSegmentStore,
786 supports_large_file_size: bool,
787 capacity: Option<usize>,
788 ) {
789 assert_eq!(store.supports_large_file_size(), supports_large_file_size);
790 assert_eq!(store.number_of_segments(), 0);
791 assert!(store.is_empty());
792 assert_eq!(store.capacity(), capacity);
793 assert_eq!(store.iter().count(), 0);
794 }
795
796 fn generic_error_tests(store: &mut impl LostSegmentStore) {
797 matches!(
798 store.add_lost_segment((0, 0)).unwrap_err(),
799 LostSegmentError::EmptySegment
800 );
801 matches!(
802 store.add_lost_segment((10, 0)).unwrap_err(),
803 LostSegmentError::StartLargerThanEnd(10, 0)
804 );
805 matches!(
806 store.remove_lost_segment((0, 0)).unwrap_err(),
807 LostSegmentError::EmptySegment
808 );
809 matches!(
810 store.remove_lost_segment((10, 0)).unwrap_err(),
811 LostSegmentError::StartLargerThanEnd(10, 0)
812 );
813 }
814
815 fn generic_add_segments_test(store: &mut impl LostSegmentStore) {
816 store.add_lost_segment((0, 20)).unwrap();
817 assert_eq!(store.number_of_segments(), 1);
818 for segment in store.iter() {
819 assert_eq!(segment, (0, 20));
820 }
821 store.add_lost_segment((20, 40)).unwrap();
822 let mut segments: Vec<(u64, u64)> = store.iter().collect();
823 segments.sort_unstable();
824 assert_eq!(segments.len(), 2);
825 assert_eq!(segments[0], (0, 20));
826 assert_eq!(segments[1], (20, 40));
827 }
828
829 fn generic_reset_test(store: &mut impl LostSegmentStore) {
830 store.add_lost_segment((0, 20)).unwrap();
831 assert_eq!(store.number_of_segments(), 1);
832 store.reset();
833 assert_eq!(store.number_of_segments(), 0);
834 assert!(store.is_empty());
835 assert_eq!(store.iter().count(), 0);
836 }
837
838 fn generic_removal_test(store: &mut impl LostSegmentStore) {
839 store.add_lost_segment((0, 20)).unwrap();
840 store.add_lost_segment((20, 40)).unwrap();
841 assert_eq!(store.number_of_segments(), 2);
842 assert!(store.remove_lost_segment((0, 20)).unwrap());
843 assert_eq!(store.number_of_segments(), 1);
844 assert!(!store.remove_lost_segment((0, 20)).unwrap());
845 assert_eq!(store.number_of_segments(), 1);
846 assert!(store.remove_lost_segment((20, 40)).unwrap());
847 assert_eq!(store.number_of_segments(), 0);
848 }
849
850 fn generic_partial_removal_test_right_aligned(store: &mut impl LostSegmentStore) {
851 store.add_lost_segment((0, 20)).unwrap();
852 assert_eq!(store.number_of_segments(), 1);
853 store.remove_lost_segment((0, 10)).unwrap();
854 assert_eq!(store.number_of_segments(), 1);
855 for list in store.iter() {
856 assert_eq!(list, (10, 20));
857 }
858 store.remove_lost_segment((10, 20)).unwrap();
859 assert!(store.is_empty());
860 }
861
862 fn generic_partial_removal_test_left_aligned(store: &mut impl LostSegmentStore) {
863 store.add_lost_segment((0, 20)).unwrap();
864 assert_eq!(store.number_of_segments(), 1);
865 store.remove_lost_segment((10, 20)).unwrap();
866 assert_eq!(store.number_of_segments(), 1);
867 for list in store.iter() {
868 assert_eq!(list, (0, 10));
869 }
870 store.remove_lost_segment((0, 10)).unwrap();
871 assert!(store.is_empty());
872 }
873
874 fn generic_partial_removal_test_fully_contained(store: &mut impl LostSegmentStore) {
875 store.add_lost_segment((0, 20)).unwrap();
876 assert_eq!(store.number_of_segments(), 1);
877 store.remove_lost_segment((5, 15)).unwrap();
878 assert_eq!(store.number_of_segments(), 2);
879 let seg_list = store.iter().collect::<Vec<(u64, u64)>>();
880 assert!(seg_list.contains(&(0, 5)));
881 assert!(seg_list.contains(&(15, 20)));
882 store.remove_lost_segment((0, 5)).unwrap();
883 assert_eq!(store.number_of_segments(), 1);
884 store.remove_lost_segment((15, 20)).unwrap();
885 assert!(store.is_empty());
886 }
887
888 fn generic_partial_removal_fails_test_0(store: &mut impl LostSegmentStore) {
889 store.add_lost_segment((10, 20)).unwrap();
890 assert_eq!(store.number_of_segments(), 1);
891 assert_eq!(
892 store.remove_lost_segment((5, 15)).unwrap_err(),
893 LostSegmentError::InvalidSegmentBoundary(5, 15)
894 );
895 }
896
897 fn generic_partial_removal_fails_test_1(store: &mut impl LostSegmentStore) {
898 store.add_lost_segment((10, 20)).unwrap();
899 assert_eq!(store.number_of_segments(), 1);
900 assert_eq!(
901 store.remove_lost_segment((15, 25)).unwrap_err(),
902 LostSegmentError::InvalidSegmentBoundary(15, 25)
903 );
904 }
905
906 fn generic_partial_removal_fails_test_2(store: &mut impl LostSegmentStore) {
907 store.add_lost_segment((10, 20)).unwrap();
908 assert_eq!(store.number_of_segments(), 1);
909 assert_eq!(
910 store.remove_lost_segment((10, 25)).unwrap_err(),
911 LostSegmentError::InvalidSegmentBoundary(10, 25)
912 );
913 }
914
915 fn generic_partial_removal_fails_test_3(store: &mut impl LostSegmentStore) {
916 store.add_lost_segment((10, 20)).unwrap();
917 assert_eq!(store.number_of_segments(), 1);
918 assert_eq!(
919 store.remove_lost_segment((5, 20)).unwrap_err(),
920 LostSegmentError::InvalidSegmentBoundary(5, 20)
921 );
922 }
923
924 fn generic_coalescing_simple_test(store: &mut impl LostSegmentStore) {
925 store.add_lost_segment((0, 20)).unwrap();
926 store.add_lost_segment((20, 40)).unwrap();
927 store.add_lost_segment((40, 60)).unwrap();
928 store.coalesce_lost_segments().unwrap();
929 for segment in store.iter() {
930 assert_eq!(segment, (0, 60));
931 }
932 assert_eq!(store.number_of_segments(), 1);
933 }
934
935 fn generic_coalescing_simple_with_gaps_test(store: &mut impl LostSegmentStore) {
936 store.add_lost_segment((0, 20)).unwrap();
937 store.add_lost_segment((20, 40)).unwrap();
938 store.add_lost_segment((40, 60)).unwrap();
939
940 store.add_lost_segment((80, 100)).unwrap();
941 store.add_lost_segment((110, 120)).unwrap();
942 store.add_lost_segment((120, 130)).unwrap();
943 store.coalesce_lost_segments().unwrap();
944 let mut segments: Vec<(u64, u64)> = store.iter().collect();
945 segments.sort_unstable();
946 assert_eq!(segments.len(), 3);
947 assert_eq!(segments[0], (0, 60));
948 assert_eq!(segments[1], (80, 100));
949 assert_eq!(segments[2], (110, 130));
950 }
951
952 fn generic_coalescing_overlapping_simple_test(store: &mut impl LostSegmentStore) {
953 store.add_lost_segment((0, 20)).unwrap();
954 store.add_lost_segment((10, 30)).unwrap();
955 store.coalesce_lost_segments().unwrap();
956 for segment in store.iter() {
957 assert_eq!(segment, (0, 30));
958 }
959 assert_eq!(store.number_of_segments(), 1);
960 }
961
962 fn generic_coalescing_overlapping_adjacent_test(store: &mut impl LostSegmentStore) {
963 store.add_lost_segment((0, 20)).unwrap();
964 store.add_lost_segment((10, 30)).unwrap();
965 store.add_lost_segment((20, 40)).unwrap();
966 store.coalesce_lost_segments().unwrap();
967 for segment in store.iter() {
968 assert_eq!(segment, (0, 40));
969 }
970 assert_eq!(store.number_of_segments(), 1);
971 }
972
973 fn generic_useless_coalescing_test(store: &mut impl LostSegmentStore) {
974 assert!(store.coalesce_lost_segments().is_ok());
976 assert_eq!(store.number_of_segments(), 0);
977 assert!(store.is_empty());
978 store.add_lost_segment((10, 20)).unwrap();
979 assert!(store.coalesce_lost_segments().is_ok());
981 for segment in store.iter() {
982 assert_eq!(segment, (10, 20));
983 }
984 }
985
986 #[test]
987 fn test_basic_map_state_list() {
988 let store = LostSegmentsList::default();
989 generic_basic_state_test(&store, true, None);
990 }
991
992 #[test]
993 fn test_basic_errors_list() {
994 let mut store = LostSegmentsList::default();
995 generic_error_tests(&mut store);
996 }
997
998 #[test]
999 fn test_add_segments_list() {
1000 let mut store = LostSegmentsList::default();
1001 generic_add_segments_test(&mut store);
1002 }
1003
1004 #[test]
1005 fn test_reset_list() {
1006 let mut store = LostSegmentsList::default();
1007 generic_reset_test(&mut store);
1008 }
1009
1010 #[test]
1011 fn test_removal_map() {
1012 let mut store = LostSegmentsList::default();
1013 generic_removal_test(&mut store);
1014 }
1015
1016 #[test]
1017 fn test_partial_removal_list_0() {
1018 let mut store = LostSegmentsList::default();
1019 generic_partial_removal_test_right_aligned(&mut store);
1020 }
1021
1022 #[test]
1023 fn test_partial_removal_list_1() {
1024 let mut store = LostSegmentsList::default();
1025 generic_partial_removal_test_left_aligned(&mut store);
1026 }
1027
1028 #[test]
1029 fn test_partial_removal_list_2() {
1030 let mut store = LostSegmentsList::default();
1031 generic_partial_removal_test_fully_contained(&mut store);
1032 }
1033
1034 #[test]
1035 fn test_partial_removal_list_fails_0() {
1036 let mut store = LostSegmentsList::default();
1037 generic_partial_removal_fails_test_0(&mut store);
1038 }
1039
1040 #[test]
1041 fn test_partial_removal_list_fails_1() {
1042 let mut store = LostSegmentsList::default();
1043 generic_partial_removal_fails_test_1(&mut store);
1044 }
1045
1046 #[test]
1047 fn test_partial_removal_list_fails_2() {
1048 let mut store = LostSegmentsList::default();
1049 generic_partial_removal_fails_test_2(&mut store);
1050 }
1051
1052 #[test]
1053 fn test_partial_removal_list_fails_3() {
1054 let mut store = LostSegmentsList::default();
1055 generic_partial_removal_fails_test_3(&mut store);
1056 }
1057
1058 #[test]
1059 fn test_cap_limit_list() {
1060 let mut store = LostSegmentsList::new(Some(4));
1061 for i in 0..4 {
1062 store.add_lost_segment((i * 20, (i + 1) * 20)).unwrap();
1063 }
1064 matches!(
1065 store.add_lost_segment((80, 100)),
1066 Err(LostSegmentError::StoreFull)
1067 );
1068 }
1069
1070 #[test]
1071 fn test_basic_list_state_list() {
1072 let store = LostSegmentsListNormalFilesHeapless::<12>::default();
1073 generic_basic_state_test(&store, false, Some(12));
1074 let store = LostSegmentsListNormalFilesHeapless::<12>::new();
1075 generic_basic_state_test(&store, false, Some(12));
1076 }
1077 #[test]
1078 fn test_basic_errors_list_heapless() {
1079 let mut store = LostSegmentsListNormalFilesHeapless::<12>::default();
1080 generic_error_tests(&mut store);
1081 }
1082
1083 #[test]
1084 fn test_add_segments_list_heapless() {
1085 let mut store = LostSegmentsListNormalFilesHeapless::<12>::default();
1086 generic_add_segments_test(&mut store);
1087 }
1088
1089 #[test]
1090 fn test_reset_list_heapless() {
1091 let mut store = LostSegmentsListNormalFilesHeapless::<12>::default();
1092 generic_reset_test(&mut store);
1093 }
1094
1095 #[test]
1096 fn test_removal_list() {
1097 let mut store = LostSegmentsListNormalFilesHeapless::<12>::default();
1098 generic_removal_test(&mut store);
1099 }
1100
1101 #[test]
1102 fn test_partial_removal_list_heapless_0() {
1103 let mut store = LostSegmentsListNormalFilesHeapless::<12>::default();
1104 generic_partial_removal_test_right_aligned(&mut store);
1105 }
1106
1107 #[test]
1108 fn test_partial_removal_list_heapless_1() {
1109 let mut store = LostSegmentsListNormalFilesHeapless::<12>::default();
1110 generic_partial_removal_test_left_aligned(&mut store);
1111 }
1112
1113 #[test]
1114 fn test_partial_removal_list_heapless_2() {
1115 let mut store = LostSegmentsListNormalFilesHeapless::<12>::default();
1116 generic_partial_removal_test_fully_contained(&mut store);
1117 }
1118
1119 #[test]
1120 fn test_partial_removal_heapless_list_fails_0() {
1121 let mut store = LostSegmentsListNormalFilesHeapless::<12>::default();
1122 generic_partial_removal_fails_test_0(&mut store);
1123 }
1124
1125 #[test]
1126 fn test_partial_removal_heapless_list_fails_1() {
1127 let mut store = LostSegmentsListNormalFilesHeapless::<12>::default();
1128 generic_partial_removal_fails_test_1(&mut store);
1129 }
1130
1131 #[test]
1132 fn test_partial_removal_heapless_list_fails_2() {
1133 let mut store = LostSegmentsListNormalFilesHeapless::<12>::default();
1134 generic_partial_removal_fails_test_2(&mut store);
1135 }
1136
1137 #[test]
1138 fn test_partial_removal_heapless_list_fails_3() {
1139 let mut store = LostSegmentsListNormalFilesHeapless::<12>::default();
1140 generic_partial_removal_fails_test_3(&mut store);
1141 }
1142
1143 fn generic_cap_limit_list_by_removal_test(store: &mut impl LostSegmentStore) {
1144 for i in 0..4 {
1145 store.add_lost_segment((i * 20, (i + 1) * 20)).unwrap();
1146 }
1147 matches!(
1149 store.remove_lost_segment((85, 95)),
1150 Err(LostSegmentError::StoreFull)
1151 );
1152 }
1153
1154 fn generic_cap_limit_list_by_addition_test(store: &mut impl LostSegmentStore) {
1155 for i in 0..4 {
1156 store.add_lost_segment((i * 20, (i + 1) * 20)).unwrap();
1157 }
1158 matches!(
1160 store.add_lost_segment((100, 120)),
1161 Err(LostSegmentError::StoreFull)
1162 );
1163 }
1164
1165 #[test]
1166 fn test_cap_limit_list_by_removal() {
1167 let mut store = LostSegmentsList::new(Some(4));
1168 generic_cap_limit_list_by_removal_test(&mut store);
1169 }
1170
1171 #[test]
1172 fn test_cap_limit_list_heapless_by_removal() {
1173 let mut store = LostSegmentsListNormalFilesHeapless::<4>::default();
1174 generic_cap_limit_list_by_removal_test(&mut store);
1175 }
1176
1177 #[test]
1178 fn test_cap_limit_list_heapless() {
1179 let mut store = LostSegmentsListNormalFilesHeapless::<4>::default();
1180 generic_cap_limit_list_by_addition_test(&mut store);
1181 }
1182
1183 #[test]
1184 fn test_large_file_size_unsupported() {
1185 let mut store = LostSegmentsListNormalFilesHeapless::<4>::default();
1186 matches!(
1187 store.add_lost_segment((0, u32::MAX as u64 + 1)),
1188 Err(LostSegmentError::LargeFileSegmentNotSupported)
1189 );
1190 }
1191
1192 #[test]
1193 fn test_large_file_size_unsupported_2() {
1194 let mut store = LostSegmentsListNormalFilesHeapless::<4>::default();
1195 matches!(
1196 store.remove_lost_segment((0, u32::MAX as u64 + 1)),
1197 Err(LostSegmentError::LargeFileSegmentNotSupported)
1198 );
1199 }
1200
1201 #[test]
1202 fn test_basic_list_state_list_large() {
1203 let store = LostSegmentsListHeapless::<12, u64>::default();
1204 generic_basic_state_test(&store, true, Some(12));
1205 }
1206 #[test]
1207 fn test_basic_errors_list_large() {
1208 let mut store = LostSegmentsListHeapless::<12, u64>::default();
1209 generic_error_tests(&mut store);
1210 }
1211
1212 #[test]
1213 fn test_add_segments_list_large() {
1214 let mut store = LostSegmentsListHeapless::<12, u64>::default();
1215 generic_add_segments_test(&mut store);
1216 }
1217
1218 #[test]
1219 fn test_reset_list_large() {
1220 let mut store = LostSegmentsListHeapless::<12, u64>::default();
1221 generic_reset_test(&mut store);
1222 }
1223
1224 #[test]
1225 fn test_removal_list_large() {
1226 let mut store = LostSegmentsListHeapless::<12, u64>::default();
1227 generic_removal_test(&mut store);
1228 }
1229
1230 #[test]
1231 fn test_partial_removal_list_heapless_large_0() {
1232 let mut store = LostSegmentsListHeapless::<12, u64>::default();
1233 generic_partial_removal_test_right_aligned(&mut store);
1234 }
1235
1236 #[test]
1237 fn test_partial_removal_list_heapless_large_1() {
1238 let mut store = LostSegmentsListHeapless::<12, u64>::default();
1239 generic_partial_removal_test_left_aligned(&mut store);
1240 }
1241
1242 #[test]
1243 fn test_partial_removal_list_heapless_large_2() {
1244 let mut store = LostSegmentsListHeapless::<12, u64>::default();
1245 generic_partial_removal_test_fully_contained(&mut store);
1246 }
1247
1248 #[test]
1249 fn test_partial_removal_heapless_list_large_fails_0() {
1250 let mut store = LostSegmentsListHeapless::<12, u64>::default();
1251 generic_partial_removal_fails_test_0(&mut store);
1252 }
1253
1254 #[test]
1255 fn test_partial_removal_heapless_list_large_fails_1() {
1256 let mut store = LostSegmentsListHeapless::<12, u64>::default();
1257 generic_partial_removal_fails_test_1(&mut store);
1258 }
1259
1260 #[test]
1261 fn test_partial_removal_heapless_list_large_fails_2() {
1262 let mut store = LostSegmentsListHeapless::<12, u64>::default();
1263 generic_partial_removal_fails_test_2(&mut store);
1264 }
1265
1266 #[test]
1267 fn test_partial_removal_heapless_list_large_fails_3() {
1268 let mut store = LostSegmentsListHeapless::<12, u64>::default();
1269 generic_partial_removal_fails_test_3(&mut store);
1270 }
1271
1272 #[test]
1273 fn test_cap_limit_list_large() {
1274 let mut store = LostSegmentsListHeapless::<4, u64>::default();
1275 generic_cap_limit_list_by_removal_test(&mut store);
1276 }
1277
1278 #[test]
1279 fn test_coalescing_simple_in_map() {
1280 let mut store = LostSegmentsList::default();
1281 generic_coalescing_simple_test(&mut store);
1282 }
1283
1284 #[test]
1285 fn test_useless_coalescing_map() {
1286 let mut store = LostSegmentsList::default();
1287 generic_useless_coalescing_test(&mut store);
1288 }
1289
1290 #[test]
1291 fn test_useless_coalescing_list() {
1292 let mut store = LostSegmentsListNormalFilesHeapless::<4>::default();
1293 generic_useless_coalescing_test(&mut store);
1294 }
1295
1296 #[test]
1297 fn test_coalescing_simple_in_list() {
1298 let mut store = LostSegmentsListNormalFilesHeapless::<4>::default();
1299 generic_coalescing_simple_test(&mut store);
1300 }
1301
1302 #[test]
1303 fn test_coalescing_simple_in_list_large() {
1304 let mut store = LostSegmentsListHeapless::<4, u64>::default();
1305 generic_coalescing_simple_test(&mut store);
1306 }
1307
1308 #[test]
1309 fn test_coalescing_overlapping_simple_in_map() {
1310 let mut store = LostSegmentsList::default();
1311 generic_coalescing_overlapping_simple_test(&mut store);
1312 }
1313
1314 #[test]
1315 fn test_coalescing_overlapping_simple_in_list() {
1316 let mut store = LostSegmentsListNormalFilesHeapless::<4>::default();
1317 generic_coalescing_overlapping_simple_test(&mut store);
1318 }
1319
1320 #[test]
1321 fn test_coalescing_overlapping_simple_in_list_large() {
1322 let mut store = LostSegmentsListHeapless::<4, u64>::default();
1323 generic_coalescing_overlapping_simple_test(&mut store);
1324 }
1325
1326 #[test]
1327 fn test_coalescing_overlapping_adjacent_in_map() {
1328 let mut store = LostSegmentsList::default();
1329 generic_coalescing_overlapping_adjacent_test(&mut store);
1330 }
1331
1332 #[test]
1333 fn test_coalescing_overlapping_adjacent_in_list() {
1334 let mut store = LostSegmentsListNormalFilesHeapless::<4>::default();
1335 generic_coalescing_overlapping_adjacent_test(&mut store);
1336 }
1337
1338 #[test]
1339 fn test_coalescing_overlapping_adjacent_in_list_large() {
1340 let mut store = LostSegmentsListHeapless::<4, u64>::default();
1341 generic_coalescing_overlapping_adjacent_test(&mut store);
1342 }
1343
1344 #[test]
1345 fn test_coalescing_simple_with_gaps_in_map() {
1346 let mut store = LostSegmentsList::default();
1347 generic_coalescing_simple_with_gaps_test(&mut store);
1348 }
1349
1350 #[test]
1351 fn test_coalescing_simple_with_gaps_in_list() {
1352 let mut store = LostSegmentsListNormalFilesHeapless::<8>::default();
1353 generic_coalescing_simple_with_gaps_test(&mut store);
1354 }
1355
1356 #[test]
1357 fn test_coalescing_simple_with_gaps_in_list_large() {
1358 let mut store = LostSegmentsListHeapless::<8, u64>::default();
1359 generic_coalescing_simple_with_gaps_test(&mut store);
1360 }
1361}