use std::path::Path;
use crate::object::{FileProvenance, ObjectSource, State};
use super::{
advance::advance_file_blame_slice,
finalize::finalize_file_provenance,
prepare::prepare_file_blame,
types::{
BlamePreparation, BlameSliceAdvance, BlameSliceError, BlameSliceLimits, BlameTarget,
OriginRange,
},
};
pub fn blame_file<S: ObjectSource>(
source: &S,
state: &State,
path: &Path,
limits: BlameSliceLimits,
) -> Result<FileProvenance, BlameSliceError> {
match prepare_file_blame(source, state, path, limits)? {
BlamePreparation::MissingPath => Err(BlameSliceError::MissingPath),
BlamePreparation::Unblamable => Err(BlameSliceError::Unblamable),
BlamePreparation::Empty { file_blob, origin } => finalize_file_provenance(
file_blob,
0,
[OriginRange {
target_start: 0,
len: 0,
origin,
}],
),
BlamePreparation::Active {
file_blob,
line_count,
mut frontier,
} => {
let expected = BlameTarget::bind(state.id(), path, file_blob, line_count)?;
frontier.require_target(&expected)?;
let mut finalized = Vec::new();
loop {
frontier.require_target(&expected)?;
match advance_file_blame_slice(source, path, frontier, limits)? {
BlameSliceAdvance::Progress {
next,
finalized: more,
..
} => {
finalized.extend(more);
frontier = next;
}
BlameSliceAdvance::Complete {
finalized: more, ..
} => {
finalized.extend(more);
break;
}
}
}
finalize_file_provenance(file_blob, line_count, finalized)
}
}
}