|
@@ -94,8 +94,7 @@ const CONTIG_COUNT: usize = 4;
|
|
/// A buffer (re)assembler.
|
|
/// A buffer (re)assembler.
|
|
///
|
|
///
|
|
/// Currently, up to a hardcoded limit of 4 or 32 holes can be tracked in the buffer.
|
|
/// Currently, up to a hardcoded limit of 4 or 32 holes can be tracked in the buffer.
|
|
-#[derive(Debug)]
|
|
|
|
-#[cfg_attr(test, derive(PartialEq, Eq, Clone))]
|
|
|
|
|
|
+#[derive(Debug, PartialEq, Eq, Clone)]
|
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
pub struct Assembler {
|
|
pub struct Assembler {
|
|
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
|
#[cfg(not(any(feature = "std", feature = "alloc")))]
|
|
@@ -139,6 +138,16 @@ impl Assembler {
|
|
self.contigs[0]
|
|
self.contigs[0]
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// Return length of the front contiguous range without removing it from the assembler
|
|
|
|
+ pub fn peek_front(&self) -> Option<usize> {
|
|
|
|
+ let front = self.front();
|
|
|
|
+ if front.has_hole() {
|
|
|
|
+ None
|
|
|
|
+ } else {
|
|
|
|
+ Some(front.data_size)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
fn back(&self) -> Contig {
|
|
fn back(&self) -> Contig {
|
|
self.contigs[self.contigs.len() - 1]
|
|
self.contigs[self.contigs.len() - 1]
|
|
}
|
|
}
|
|
@@ -182,10 +191,12 @@ impl Assembler {
|
|
Ok(&mut self.contigs[at])
|
|
Ok(&mut self.contigs[at])
|
|
}
|
|
}
|
|
|
|
|
|
- /// Add a new contiguous range to the assembler, and return `Ok(())`,
|
|
|
|
|
|
+ /// Add a new contiguous range to the assembler, and return `Ok(bool)`,
|
|
/// or return `Err(())` if too many discontiguities are already recorded.
|
|
/// or return `Err(())` if too many discontiguities are already recorded.
|
|
- pub fn add(&mut self, mut offset: usize, mut size: usize) -> Result<(), TooManyHolesError> {
|
|
|
|
|
|
+ /// Returns `Ok(true)` when there was an overlap.
|
|
|
|
+ pub fn add(&mut self, mut offset: usize, mut size: usize) -> Result<bool, TooManyHolesError> {
|
|
let mut index = 0;
|
|
let mut index = 0;
|
|
|
|
+ let mut overlap = size;
|
|
while index != self.contigs.len() && size != 0 {
|
|
while index != self.contigs.len() && size != 0 {
|
|
let contig = self.contigs[index];
|
|
let contig = self.contigs[index];
|
|
|
|
|
|
@@ -196,6 +207,7 @@ impl Assembler {
|
|
// The range being added covers the entire hole in this contig, merge it
|
|
// The range being added covers the entire hole in this contig, merge it
|
|
// into the previous config.
|
|
// into the previous config.
|
|
self.contigs[index - 1].expand_data_by(contig.total_size());
|
|
self.contigs[index - 1].expand_data_by(contig.total_size());
|
|
|
|
+ overlap -= contig.total_size();
|
|
self.remove_contig_at(index);
|
|
self.remove_contig_at(index);
|
|
index += 0;
|
|
index += 0;
|
|
} else if offset == 0 && size < contig.hole_size && index > 0 {
|
|
} else if offset == 0 && size < contig.hole_size && index > 0 {
|
|
@@ -204,10 +216,12 @@ impl Assembler {
|
|
// the previous contig.
|
|
// the previous contig.
|
|
self.contigs[index - 1].expand_data_by(size);
|
|
self.contigs[index - 1].expand_data_by(size);
|
|
self.contigs[index].shrink_hole_by(size);
|
|
self.contigs[index].shrink_hole_by(size);
|
|
|
|
+ overlap -= size;
|
|
index += 1;
|
|
index += 1;
|
|
} else if offset <= contig.hole_size && offset + size >= contig.hole_size {
|
|
} else if offset <= contig.hole_size && offset + size >= contig.hole_size {
|
|
// The range being added covers both a part of the hole and a part of the data
|
|
// The range being added covers both a part of the hole and a part of the data
|
|
// in this contig, shrink the hole in this contig.
|
|
// in this contig, shrink the hole in this contig.
|
|
|
|
+ overlap -= contig.hole_size - offset;
|
|
self.contigs[index].shrink_hole_to(offset);
|
|
self.contigs[index].shrink_hole_to(offset);
|
|
index += 1;
|
|
index += 1;
|
|
} else if offset + size >= contig.hole_size {
|
|
} else if offset + size >= contig.hole_size {
|
|
@@ -219,6 +233,7 @@ impl Assembler {
|
|
{
|
|
{
|
|
let inserted = self.add_contig_at(index)?;
|
|
let inserted = self.add_contig_at(index)?;
|
|
*inserted = Contig::hole_and_data(offset, size);
|
|
*inserted = Contig::hole_and_data(offset, size);
|
|
|
|
+ overlap -= size;
|
|
}
|
|
}
|
|
// Previous contigs[index] got moved to contigs[index+1]
|
|
// Previous contigs[index] got moved to contigs[index+1]
|
|
self.contigs[index + 1].shrink_hole_by(offset + size);
|
|
self.contigs[index + 1].shrink_hole_by(offset + size);
|
|
@@ -237,7 +252,7 @@ impl Assembler {
|
|
}
|
|
}
|
|
|
|
|
|
debug_assert!(size == 0);
|
|
debug_assert!(size == 0);
|
|
- Ok(())
|
|
|
|
|
|
+ Ok(overlap != 0)
|
|
}
|
|
}
|
|
|
|
|
|
/// Remove a contiguous range from the front of the assembler and `Some(data_size)`,
|
|
/// Remove a contiguous range from the front of the assembler and `Some(data_size)`,
|
|
@@ -280,8 +295,8 @@ pub struct AssemblerIter<'a> {
|
|
impl<'a> AssemblerIter<'a> {
|
|
impl<'a> AssemblerIter<'a> {
|
|
fn new(assembler: &'a Assembler, offset: usize) -> AssemblerIter<'a> {
|
|
fn new(assembler: &'a Assembler, offset: usize) -> AssemblerIter<'a> {
|
|
AssemblerIter {
|
|
AssemblerIter {
|
|
- assembler: assembler,
|
|
|
|
- offset: offset,
|
|
|
|
|
|
+ assembler,
|
|
|
|
+ offset,
|
|
index: 0,
|
|
index: 0,
|
|
left: 0,
|
|
left: 0,
|
|
right: 0,
|
|
right: 0,
|
|
@@ -348,84 +363,84 @@ mod test {
|
|
#[test]
|
|
#[test]
|
|
fn test_empty_add_full() {
|
|
fn test_empty_add_full() {
|
|
let mut assr = Assembler::new(16);
|
|
let mut assr = Assembler::new(16);
|
|
- assert_eq!(assr.add(0, 16), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(0, 16), Ok(false));
|
|
assert_eq!(assr, contigs![(0, 16)]);
|
|
assert_eq!(assr, contigs![(0, 16)]);
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_empty_add_front() {
|
|
fn test_empty_add_front() {
|
|
let mut assr = Assembler::new(16);
|
|
let mut assr = Assembler::new(16);
|
|
- assert_eq!(assr.add(0, 4), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(0, 4), Ok(false));
|
|
assert_eq!(assr, contigs![(0, 4), (12, 0)]);
|
|
assert_eq!(assr, contigs![(0, 4), (12, 0)]);
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_empty_add_back() {
|
|
fn test_empty_add_back() {
|
|
let mut assr = Assembler::new(16);
|
|
let mut assr = Assembler::new(16);
|
|
- assert_eq!(assr.add(12, 4), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(12, 4), Ok(false));
|
|
assert_eq!(assr, contigs![(12, 4)]);
|
|
assert_eq!(assr, contigs![(12, 4)]);
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_empty_add_mid() {
|
|
fn test_empty_add_mid() {
|
|
let mut assr = Assembler::new(16);
|
|
let mut assr = Assembler::new(16);
|
|
- assert_eq!(assr.add(4, 8), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(4, 8), Ok(false));
|
|
assert_eq!(assr, contigs![(4, 8), (4, 0)]);
|
|
assert_eq!(assr, contigs![(4, 8), (4, 0)]);
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_partial_add_front() {
|
|
fn test_partial_add_front() {
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
- assert_eq!(assr.add(0, 4), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(0, 4), Ok(false));
|
|
assert_eq!(assr, contigs![(0, 12), (4, 0)]);
|
|
assert_eq!(assr, contigs![(0, 12), (4, 0)]);
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_partial_add_back() {
|
|
fn test_partial_add_back() {
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
- assert_eq!(assr.add(12, 4), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(12, 4), Ok(false));
|
|
assert_eq!(assr, contigs![(4, 12)]);
|
|
assert_eq!(assr, contigs![(4, 12)]);
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_partial_add_front_overlap() {
|
|
fn test_partial_add_front_overlap() {
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
- assert_eq!(assr.add(0, 8), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(0, 8), Ok(true));
|
|
assert_eq!(assr, contigs![(0, 12), (4, 0)]);
|
|
assert_eq!(assr, contigs![(0, 12), (4, 0)]);
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_partial_add_front_overlap_split() {
|
|
fn test_partial_add_front_overlap_split() {
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
- assert_eq!(assr.add(2, 6), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(2, 6), Ok(true));
|
|
assert_eq!(assr, contigs![(2, 10), (4, 0)]);
|
|
assert_eq!(assr, contigs![(2, 10), (4, 0)]);
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_partial_add_back_overlap() {
|
|
fn test_partial_add_back_overlap() {
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
- assert_eq!(assr.add(8, 8), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(8, 8), Ok(true));
|
|
assert_eq!(assr, contigs![(4, 12)]);
|
|
assert_eq!(assr, contigs![(4, 12)]);
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_partial_add_back_overlap_split() {
|
|
fn test_partial_add_back_overlap_split() {
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
- assert_eq!(assr.add(10, 4), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(10, 4), Ok(true));
|
|
assert_eq!(assr, contigs![(4, 10), (2, 0)]);
|
|
assert_eq!(assr, contigs![(4, 10), (2, 0)]);
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_partial_add_both_overlap() {
|
|
fn test_partial_add_both_overlap() {
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
- assert_eq!(assr.add(0, 16), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(0, 16), Ok(true));
|
|
assert_eq!(assr, contigs![(0, 16)]);
|
|
assert_eq!(assr, contigs![(0, 16)]);
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_partial_add_both_overlap_split() {
|
|
fn test_partial_add_both_overlap_split() {
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
let mut assr = contigs![(4, 8), (4, 0)];
|
|
- assert_eq!(assr.add(2, 12), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(2, 12), Ok(true));
|
|
assert_eq!(assr, contigs![(2, 12), (2, 0)]);
|
|
assert_eq!(assr, contigs![(2, 12), (2, 0)]);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -433,7 +448,7 @@ mod test {
|
|
fn test_rejected_add_keeps_state() {
|
|
fn test_rejected_add_keeps_state() {
|
|
let mut assr = Assembler::new(CONTIG_COUNT * 20);
|
|
let mut assr = Assembler::new(CONTIG_COUNT * 20);
|
|
for c in 1..=CONTIG_COUNT - 1 {
|
|
for c in 1..=CONTIG_COUNT - 1 {
|
|
- assert_eq!(assr.add(c * 10, 3), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(c * 10, 3), Ok(false));
|
|
}
|
|
}
|
|
// Maximum of allowed holes is reached
|
|
// Maximum of allowed holes is reached
|
|
let assr_before = assr.clone();
|
|
let assr_before = assr.clone();
|
|
@@ -471,7 +486,7 @@ mod test {
|
|
#[test]
|
|
#[test]
|
|
fn test_iter_full() {
|
|
fn test_iter_full() {
|
|
let mut assr = Assembler::new(16);
|
|
let mut assr = Assembler::new(16);
|
|
- assert_eq!(assr.add(0, 16), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(0, 16), Ok(false));
|
|
let segments: Vec<_> = assr.iter_data(10).collect();
|
|
let segments: Vec<_> = assr.iter_data(10).collect();
|
|
assert_eq!(segments, vec![(10, 26)]);
|
|
assert_eq!(segments, vec![(10, 26)]);
|
|
}
|
|
}
|
|
@@ -479,7 +494,7 @@ mod test {
|
|
#[test]
|
|
#[test]
|
|
fn test_iter_offset() {
|
|
fn test_iter_offset() {
|
|
let mut assr = Assembler::new(16);
|
|
let mut assr = Assembler::new(16);
|
|
- assert_eq!(assr.add(0, 16), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(0, 16), Ok(false));
|
|
let segments: Vec<_> = assr.iter_data(100).collect();
|
|
let segments: Vec<_> = assr.iter_data(100).collect();
|
|
assert_eq!(segments, vec![(100, 116)]);
|
|
assert_eq!(segments, vec![(100, 116)]);
|
|
}
|
|
}
|
|
@@ -487,7 +502,7 @@ mod test {
|
|
#[test]
|
|
#[test]
|
|
fn test_iter_one_front() {
|
|
fn test_iter_one_front() {
|
|
let mut assr = Assembler::new(16);
|
|
let mut assr = Assembler::new(16);
|
|
- assert_eq!(assr.add(0, 4), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(0, 4), Ok(false));
|
|
let segments: Vec<_> = assr.iter_data(10).collect();
|
|
let segments: Vec<_> = assr.iter_data(10).collect();
|
|
assert_eq!(segments, vec![(10, 14)]);
|
|
assert_eq!(segments, vec![(10, 14)]);
|
|
}
|
|
}
|
|
@@ -495,7 +510,7 @@ mod test {
|
|
#[test]
|
|
#[test]
|
|
fn test_iter_one_back() {
|
|
fn test_iter_one_back() {
|
|
let mut assr = Assembler::new(16);
|
|
let mut assr = Assembler::new(16);
|
|
- assert_eq!(assr.add(12, 4), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(12, 4), Ok(false));
|
|
let segments: Vec<_> = assr.iter_data(10).collect();
|
|
let segments: Vec<_> = assr.iter_data(10).collect();
|
|
assert_eq!(segments, vec![(22, 26)]);
|
|
assert_eq!(segments, vec![(22, 26)]);
|
|
}
|
|
}
|
|
@@ -503,7 +518,7 @@ mod test {
|
|
#[test]
|
|
#[test]
|
|
fn test_iter_one_mid() {
|
|
fn test_iter_one_mid() {
|
|
let mut assr = Assembler::new(16);
|
|
let mut assr = Assembler::new(16);
|
|
- assert_eq!(assr.add(4, 8), Ok(()));
|
|
|
|
|
|
+ assert_eq!(assr.add(4, 8), Ok(false));
|
|
let segments: Vec<_> = assr.iter_data(10).collect();
|
|
let segments: Vec<_> = assr.iter_data(10).collect();
|
|
assert_eq!(segments, vec![(14, 22)]);
|
|
assert_eq!(segments, vec![(14, 22)]);
|
|
}
|
|
}
|