use crate::Error;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LineSearchStep {
CompareThroughLine {
line: u64,
},
DifferenceAtLine {
line: u64,
},
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct LineSearch {
bounds: SearchBounds,
}
impl LineSearch {
pub fn new(local_line_count: u64, other_line_count: u64) -> Result<Self, Error> {
let bounds = SearchBounds::new(local_line_count.max(other_line_count))
.ok_or(Error::EmptyFilesCannotDiffer)?;
Ok(Self { bounds })
}
pub fn current_step(&self) -> LineSearchStep {
match self.bounds.midpoint() {
Some(line) => LineSearchStep::CompareThroughLine { line },
None => LineSearchStep::DifferenceAtLine {
line: self.bounds.low,
},
}
}
pub fn record_result(&mut self, matched: bool) -> Result<(), Error> {
self.bounds.record_result(matched)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ByteSearchStep {
CompareThroughByte {
byte: u64,
},
DifferenceAtByte {
byte: u64,
},
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ByteSearch {
bounds: SearchBounds,
}
impl ByteSearch {
pub fn new(local_byte_len: u64, other_byte_len: u64) -> Result<Self, Error> {
let bounds = SearchBounds::new(local_byte_len.max(other_byte_len))
.ok_or(Error::EmptyLinesCannotDiffer)?;
Ok(Self { bounds })
}
pub fn current_step(&self) -> ByteSearchStep {
match self.bounds.midpoint() {
Some(byte) => ByteSearchStep::CompareThroughByte { byte },
None => ByteSearchStep::DifferenceAtByte {
byte: self.bounds.low,
},
}
}
pub fn record_result(&mut self, matched: bool) -> Result<(), Error> {
self.bounds.record_result(matched)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct SearchBounds {
low: u64,
high: u64,
}
impl SearchBounds {
fn new(high: u64) -> Option<Self> {
(high > 0).then_some(Self { low: 1, high })
}
fn midpoint(&self) -> Option<u64> {
(self.low < self.high).then(|| self.low + (self.high - self.low) / 2)
}
fn record_result(&mut self, matched: bool) -> Result<(), Error> {
let midpoint = self.midpoint().ok_or(Error::SearchAlreadyComplete)?;
if matched {
self.low = midpoint + 1;
} else {
self.high = midpoint;
}
Ok(())
}
}