1use std::path::Path;
5
6use crate::object::{FileProvenance, ObjectSource, State};
7
8use super::{
9 advance::advance_file_blame_slice,
10 finalize::finalize_file_provenance,
11 prepare::prepare_file_blame,
12 types::{
13 BlamePreparation, BlameSliceAdvance, BlameSliceError, BlameSliceLimits, BlameTarget,
14 OriginRange,
15 },
16};
17
18pub fn blame_file<S: ObjectSource>(
22 source: &S,
23 state: &State,
24 path: &Path,
25 limits: BlameSliceLimits,
26) -> Result<FileProvenance, BlameSliceError> {
27 match prepare_file_blame(source, state, path, limits)? {
28 BlamePreparation::MissingPath => Err(BlameSliceError::MissingPath),
29 BlamePreparation::Unblamable => Err(BlameSliceError::Unblamable),
30 BlamePreparation::Empty { file_blob, origin } => finalize_file_provenance(
31 file_blob,
32 0,
33 [OriginRange {
34 target_start: 0,
35 len: 0,
36 origin,
37 }],
38 ),
39 BlamePreparation::Active {
40 file_blob,
41 line_count,
42 mut frontier,
43 } => {
44 let expected = BlameTarget::bind(state.id(), path, file_blob, line_count)?;
45 frontier.require_target(&expected)?;
46 let mut finalized = Vec::new();
47 loop {
48 frontier.require_target(&expected)?;
49 match advance_file_blame_slice(source, path, frontier, limits)? {
50 BlameSliceAdvance::Progress {
51 next,
52 finalized: more,
53 ..
54 } => {
55 finalized.extend(more);
56 frontier = next;
57 }
58 BlameSliceAdvance::Complete {
59 finalized: more, ..
60 } => {
61 finalized.extend(more);
62 break;
63 }
64 }
65 }
66 finalize_file_provenance(file_blob, line_count, finalized)
67 }
68 }
69}