CLeanup, and get domain overlap and mapping adjustment working.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
use super::{Cluster, Domain, Stage};
|
||||
use super::{Cluster, Domain, DomainOverlap, Stage};
|
||||
|
||||
use anyhow;
|
||||
use ron::de::from_reader;
|
||||
@@ -47,66 +47,32 @@ impl MapFile {
|
||||
}
|
||||
|
||||
/// Recalculate cluster mappings.
|
||||
pub fn update(&mut self, new_cluster: Cluster) -> &mut Self {
|
||||
let mut new_map: Vec<Cluster> = vec![Cluster::from(new_cluster.to_owned())];
|
||||
pub fn update(&mut self, new: Cluster) -> &mut Self {
|
||||
let mut map: Vec<Cluster> = vec![Cluster::from(new.clone())];
|
||||
|
||||
for map_cluster in self.map.iter() {
|
||||
let mut map_cluster = *map_cluster;
|
||||
for old in self.map.iter() {
|
||||
let mut old = *old;
|
||||
|
||||
// If new_cluster doesn't start ahead and ends short, map_cluster is forgotten.
|
||||
if new_cluster.domain.start < map_cluster.domain.start
|
||||
&& new_cluster.domain.end < map_cluster.domain.end
|
||||
{
|
||||
/*
|
||||
new_cluster overlaps the start of map_cluster,
|
||||
but ends short of map_cluster end.
|
||||
|
||||
ACTION: Crop map_cluster to start at end of new_cluster.
|
||||
*/
|
||||
|
||||
map_cluster.domain.start = new_cluster.domain.end;
|
||||
new_map.push(map_cluster);
|
||||
} else if new_cluster.domain.end < map_cluster.domain.end {
|
||||
/*
|
||||
new_cluster starts within map_cluster domain.
|
||||
|
||||
ACTION: Crop
|
||||
*/
|
||||
|
||||
let domain_end = map_cluster.domain.end;
|
||||
|
||||
// Crop current object.
|
||||
map_cluster.domain.end = new_cluster.domain.start;
|
||||
new_map.push(map_cluster);
|
||||
|
||||
if new_cluster.domain.end < map_cluster.domain.end {
|
||||
/*
|
||||
new_cluster is within map_cluster.
|
||||
|
||||
ACTION: Crop & Fracture map_cluster
|
||||
NOTE: Crop completed above.
|
||||
*/
|
||||
|
||||
new_map.push(Cluster {
|
||||
domain: Domain {
|
||||
start: new_cluster.domain.end,
|
||||
end: domain_end,
|
||||
},
|
||||
stage: map_cluster.stage.to_owned(),
|
||||
});
|
||||
match new.domain.overlap(old.domain) {
|
||||
DomainOverlap::None => map.push(old),
|
||||
DomainOverlap::SelfEngulfsOther => (),
|
||||
DomainOverlap::OtherEngulfsSelf => {
|
||||
other_engulfs_self_update(new, &mut old, &mut map)
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
No overlap.
|
||||
|
||||
ACTION: Transfer
|
||||
*/
|
||||
|
||||
new_map.push(map_cluster);
|
||||
}
|
||||
DomainOverlap::OtherOverlapsEnd => {
|
||||
// Case 1
|
||||
old.domain.start = new.domain.end;
|
||||
map.push(old);
|
||||
}
|
||||
DomainOverlap::OtherOverlapsStart => {
|
||||
// Case 2
|
||||
old.domain.end = new.domain.start;
|
||||
map.push(old);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
self.map = new_map;
|
||||
self.map = map;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -126,7 +92,7 @@ impl MapFile {
|
||||
}
|
||||
}
|
||||
Stage::Damaged => (),
|
||||
Stage::Intact => unreachable!(),
|
||||
Stage::Intact => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +163,29 @@ impl MapFile {
|
||||
self.map = new_map;
|
||||
self
|
||||
}
|
||||
|
||||
/// Extend the domain of the MapFile.
|
||||
/// Returns None if the domain cannot be changed or is unchanged.
|
||||
/// Returns the delta of the previous domain end and the new end.
|
||||
pub fn extend(&mut self, end: usize) -> Option<usize> {
|
||||
if end <= self.domain.end {
|
||||
return None;
|
||||
}
|
||||
|
||||
let old_end = self.domain.end;
|
||||
let delta = end - old_end;
|
||||
self.domain.end = end;
|
||||
|
||||
// Add new data as untested.
|
||||
self.update(Cluster {
|
||||
domain: Domain {
|
||||
start: old_end,
|
||||
end: self.domain.end,
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
Some(delta)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_map_to_file(file: &mut File, map: &MapFile) -> anyhow::Result<usize> {
|
||||
@@ -213,17 +202,522 @@ pub fn write_map_to_file(file: &mut File, map: &MapFile) -> anyhow::Result<usize
|
||||
Ok(written_bytes)
|
||||
}
|
||||
|
||||
fn other_engulfs_self_update(new: Cluster, old: &mut Cluster, map: &mut Vec<Cluster>) {
|
||||
if new.domain.start == old.domain.start {
|
||||
// Case 6 of map::tests::test_update
|
||||
old.domain.start = new.domain.end;
|
||||
} else {
|
||||
// Case 4 and part of 10
|
||||
|
||||
let old_end = old.domain.end;
|
||||
old.domain.end = new.domain.start;
|
||||
|
||||
if new.domain.end != old_end {
|
||||
// Case 10 of map::tests::test_update
|
||||
map.push(Cluster {
|
||||
domain: Domain {
|
||||
start: new.domain.end,
|
||||
end: old_end,
|
||||
},
|
||||
stage: old.stage,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
map.push(old.to_owned())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashSet;
|
||||
|
||||
use super::*;
|
||||
|
||||
// Test for MapFile::update()
|
||||
|
||||
// Test for MapFile::get_stage()
|
||||
/// Test for MapFile::update()
|
||||
#[test]
|
||||
fn test_get_stage() {
|
||||
use std::vec;
|
||||
fn update_1_new_overlaps_start() {
|
||||
// Case 1:
|
||||
// |----new----|
|
||||
// |----old----|
|
||||
//
|
||||
// | --> |-old-|
|
||||
// Solution: old.start = new.end
|
||||
|
||||
let mut map = MapFile {
|
||||
map: vec![Cluster {
|
||||
domain: Domain { start: 1, end: 3 },
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
map.update(Cluster {
|
||||
domain: Domain { start: 0, end: 2 },
|
||||
..Default::default()
|
||||
});
|
||||
map.map.sort();
|
||||
|
||||
assert_eq!(
|
||||
map.map,
|
||||
vec![
|
||||
Cluster {
|
||||
domain: Domain { start: 0, end: 2 },
|
||||
..Default::default()
|
||||
},
|
||||
Cluster {
|
||||
domain: Domain { start: 2, end: 3 },
|
||||
..Default::default()
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for MapFile::update()
|
||||
#[test]
|
||||
fn update_2_new_overlaps_end() {
|
||||
// Case 2:
|
||||
// |----new----|
|
||||
// |----old----|
|
||||
//
|
||||
// |-old-| <-- |
|
||||
// Solution: old.end = new.start
|
||||
|
||||
let mut map = MapFile {
|
||||
map: vec![Cluster {
|
||||
domain: Domain { start: 0, end: 2 },
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
map.update(Cluster {
|
||||
domain: Domain { start: 1, end: 3 },
|
||||
..Default::default()
|
||||
});
|
||||
map.map.sort();
|
||||
|
||||
assert_eq!(
|
||||
map.map,
|
||||
vec![
|
||||
Cluster {
|
||||
domain: Domain { start: 0, end: 1 },
|
||||
..Default::default()
|
||||
},
|
||||
Cluster {
|
||||
domain: Domain { start: 1, end: 3 },
|
||||
..Default::default()
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for MapFile::update()
|
||||
#[test]
|
||||
fn update_3_new_engulfs_common_end() {
|
||||
// Case 3:
|
||||
// |----new----|
|
||||
// |--old--|
|
||||
//
|
||||
// Solution: Remove old.
|
||||
|
||||
let mut map = MapFile {
|
||||
map: vec![Cluster {
|
||||
domain: Domain { start: 1, end: 3 },
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
map.update(Cluster {
|
||||
domain: Domain { start: 0, end: 3 },
|
||||
..Default::default()
|
||||
});
|
||||
map.map.sort();
|
||||
|
||||
assert_eq!(
|
||||
map.map,
|
||||
vec![Cluster {
|
||||
domain: Domain { start: 0, end: 3 },
|
||||
..Default::default()
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for MapFile::update()
|
||||
#[test]
|
||||
fn update_4_old_engulfs_common_end() {
|
||||
// Case 4:
|
||||
// |--new--|
|
||||
// |-----old-----|
|
||||
//
|
||||
// |-old-| <---- |
|
||||
// Solution: old.end = new.start
|
||||
|
||||
let mut map = MapFile {
|
||||
map: vec![Cluster {
|
||||
domain: Domain { start: 0, end: 3 },
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
map.update(Cluster {
|
||||
domain: Domain { start: 1, end: 3 },
|
||||
..Default::default()
|
||||
});
|
||||
map.map.sort();
|
||||
|
||||
assert_eq!(
|
||||
map.map,
|
||||
vec![
|
||||
Cluster {
|
||||
domain: Domain { start: 0, end: 1 },
|
||||
..Default::default()
|
||||
},
|
||||
Cluster {
|
||||
domain: Domain { start: 1, end: 3 },
|
||||
..Default::default()
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for MapFile::update()
|
||||
#[test]
|
||||
fn update_5_new_engulfs_common_start() {
|
||||
// Case 5:
|
||||
// |-----new----|
|
||||
// |--old--|
|
||||
//
|
||||
// Solution: Remove old.
|
||||
|
||||
let mut map = MapFile {
|
||||
map: vec![Cluster {
|
||||
domain: Domain { start: 0, end: 2 },
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
map.update(Cluster {
|
||||
domain: Domain { start: 0, end: 3 },
|
||||
..Default::default()
|
||||
});
|
||||
map.map.sort();
|
||||
|
||||
assert_eq!(
|
||||
map.map,
|
||||
vec![Cluster {
|
||||
domain: Domain { start: 0, end: 3 },
|
||||
..Default::default()
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for MapFile::update()
|
||||
#[test]
|
||||
fn update_6_old_engulfs_common_start() {
|
||||
// Case 6:
|
||||
// |--new--|
|
||||
// |-----old-----|
|
||||
//
|
||||
// | ----> |-old-|
|
||||
// Solution: old.start = new.end
|
||||
|
||||
let mut map = MapFile {
|
||||
map: vec![Cluster {
|
||||
domain: Domain { start: 0, end: 3 },
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
map.update(Cluster {
|
||||
domain: Domain { start: 0, end: 2 },
|
||||
..Default::default()
|
||||
});
|
||||
map.map.sort();
|
||||
|
||||
assert_eq!(
|
||||
map.map,
|
||||
vec![
|
||||
Cluster {
|
||||
domain: Domain { start: 0, end: 2 },
|
||||
..Default::default()
|
||||
},
|
||||
Cluster {
|
||||
domain: Domain { start: 2, end: 3 },
|
||||
..Default::default()
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for MapFile::update()
|
||||
#[test]
|
||||
fn update_7_new_precedes() {
|
||||
// Case 7:
|
||||
// |--new--|
|
||||
// |--old--|
|
||||
//
|
||||
// Solution: Leave unchanged.
|
||||
|
||||
let mut map = MapFile {
|
||||
map: vec![Cluster {
|
||||
domain: Domain { start: 2, end: 3 },
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
map.update(Cluster {
|
||||
domain: Domain { start: 0, end: 2 },
|
||||
..Default::default()
|
||||
});
|
||||
map.map.sort();
|
||||
|
||||
assert_eq!(
|
||||
map.map,
|
||||
vec![
|
||||
Cluster {
|
||||
domain: Domain { start: 0, end: 2 },
|
||||
..Default::default()
|
||||
},
|
||||
Cluster {
|
||||
domain: Domain { start: 2, end: 3 },
|
||||
..Default::default()
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for MapFile::update()
|
||||
#[test]
|
||||
fn update_8_new_trails() {
|
||||
// Case 8:
|
||||
// |--new--|
|
||||
// |--old--|
|
||||
// Solution: Leave unchanged.
|
||||
|
||||
let mut map = MapFile {
|
||||
map: vec![Cluster {
|
||||
domain: Domain { start: 0, end: 2 },
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
map.update(Cluster {
|
||||
domain: Domain { start: 2, end: 3 },
|
||||
..Default::default()
|
||||
});
|
||||
map.map.sort();
|
||||
|
||||
assert_eq!(
|
||||
map.map,
|
||||
vec![
|
||||
Cluster {
|
||||
domain: Domain { start: 0, end: 2 },
|
||||
..Default::default()
|
||||
},
|
||||
Cluster {
|
||||
domain: Domain { start: 2, end: 3 },
|
||||
..Default::default()
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for MapFile::update()
|
||||
#[test]
|
||||
fn update_9_new_engulfs() {
|
||||
// Case 9:
|
||||
// |-----new-----|
|
||||
// |--old--|
|
||||
//
|
||||
// Solution: Remove old.
|
||||
|
||||
let mut map = MapFile {
|
||||
map: vec![Cluster {
|
||||
domain: Domain { start: 1, end: 2 },
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
map.update(Cluster {
|
||||
domain: Domain { start: 0, end: 3 },
|
||||
..Default::default()
|
||||
});
|
||||
map.map.sort();
|
||||
|
||||
assert_eq!(
|
||||
map.map,
|
||||
vec![Cluster {
|
||||
domain: Domain { start: 0, end: 3 },
|
||||
..Default::default()
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for MapFile::update()
|
||||
#[test]
|
||||
fn update_10_old_engulfs() {
|
||||
// Case 10:
|
||||
// |--new--|
|
||||
// |--------------old--------------|
|
||||
//
|
||||
// |----old----| <---- |
|
||||
// + |--fracture-|
|
||||
// Solution: old.end = new.start
|
||||
// && fracture:
|
||||
// with fracture.start = new.end
|
||||
// && fracture.end = old.original_end
|
||||
|
||||
let mut map = MapFile {
|
||||
map: vec![Cluster {
|
||||
domain: Domain { start: 0, end: 3 },
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
map.update(Cluster {
|
||||
domain: Domain { start: 1, end: 2 },
|
||||
..Default::default()
|
||||
});
|
||||
map.map.sort();
|
||||
|
||||
assert_eq!(
|
||||
map.map,
|
||||
vec![
|
||||
Cluster {
|
||||
domain: Domain { start: 0, end: 1 },
|
||||
..Default::default()
|
||||
},
|
||||
Cluster {
|
||||
domain: Domain { start: 1, end: 2 },
|
||||
..Default::default()
|
||||
},
|
||||
Cluster {
|
||||
domain: Domain { start: 2, end: 3 },
|
||||
..Default::default()
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for MapFile::update()
|
||||
#[test]
|
||||
fn update_11_common_start_and_end() {
|
||||
// Case 11:
|
||||
// |--new--|
|
||||
// |--old--|
|
||||
//
|
||||
// Solution: Remove old.
|
||||
|
||||
let mut map = MapFile {
|
||||
map: vec![Cluster {
|
||||
domain: Domain { start: 0, end: 3 },
|
||||
stage: Stage::Untested,
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
map.update(Cluster {
|
||||
domain: Domain { start: 0, end: 3 },
|
||||
stage: Stage::Intact,
|
||||
});
|
||||
map.map.sort();
|
||||
|
||||
assert_eq!(
|
||||
map.map,
|
||||
vec![Cluster {
|
||||
domain: Domain { start: 0, end: 3 },
|
||||
stage: Stage::Intact
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for MapFile::update()
|
||||
#[test]
|
||||
fn update_12_new_out_of_range_preceding() {
|
||||
// Case 12:
|
||||
// |--new--|
|
||||
// |--old--|
|
||||
//
|
||||
// Solution: Leave Unchanged.
|
||||
|
||||
let mut map = MapFile {
|
||||
map: vec![Cluster {
|
||||
domain: Domain { start: 2, end: 3 },
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
map.update(Cluster {
|
||||
domain: Domain { start: 0, end: 1 },
|
||||
..Default::default()
|
||||
});
|
||||
map.map.sort();
|
||||
|
||||
assert_eq!(
|
||||
map.map,
|
||||
vec![
|
||||
Cluster {
|
||||
domain: Domain { start: 0, end: 1 },
|
||||
..Default::default()
|
||||
},
|
||||
Cluster {
|
||||
domain: Domain { start: 2, end: 3 },
|
||||
..Default::default()
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for MapFile::update()
|
||||
#[test]
|
||||
fn update_13_new_out_of_range_trailing() {
|
||||
// Case 13:
|
||||
// |--new--|
|
||||
// |--old--|
|
||||
//
|
||||
// Solution: Leave Unchanged.
|
||||
|
||||
let mut map = MapFile {
|
||||
map: vec![Cluster {
|
||||
domain: Domain { start: 0, end: 1 },
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
map.update(Cluster {
|
||||
domain: Domain { start: 2, end: 3 },
|
||||
..Default::default()
|
||||
});
|
||||
map.map.sort();
|
||||
|
||||
assert_eq!(
|
||||
map.map,
|
||||
vec![
|
||||
Cluster {
|
||||
domain: Domain { start: 0, end: 1 },
|
||||
..Default::default()
|
||||
},
|
||||
Cluster {
|
||||
domain: Domain { start: 2, end: 3 },
|
||||
..Default::default()
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for MapFile::get_stage()
|
||||
#[test]
|
||||
fn get_stage() {
|
||||
let mut mf = MapFile::default();
|
||||
let mut mf_stage = mf.get_stage();
|
||||
|
||||
@@ -258,9 +752,9 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
// Test for MapFile::get_clusters()
|
||||
/// Test for MapFile::get_clusters()
|
||||
#[test]
|
||||
fn test_get_clusters() {
|
||||
fn get_clusters() {
|
||||
let mut mf = MapFile::default();
|
||||
|
||||
mf.map = vec![
|
||||
@@ -297,9 +791,9 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
// Test for MapFile::defrag()
|
||||
/// Test for MapFile::defrag()
|
||||
#[test]
|
||||
fn test_defrag() {
|
||||
fn defrag() {
|
||||
let mut mf = MapFile {
|
||||
sector_size: 1,
|
||||
domain: Domain { start: 0, end: 8 },
|
||||
|
||||
Reference in New Issue
Block a user