diff.rs
use crate::{hash_one, repo, AHash};
use std::borrow::Cow;
#[derive(Debug)]
pub enum FileContent<'a> {
Decoded(Cow<'a, str>),
Image(Vec<u8>),
UnknownEncoding,
}
#[derive(Debug)]
pub enum File {
Decoded(DecodedFile),
Undecodable(UndecodableFile),
Image(Vec<u8>),
}
#[derive(Debug)]
pub struct DecodedFile {
pub combined: Combined,
pub diffs_without_contents: Vec<DiffWithoutContents>,
}
#[derive(Debug)]
pub struct UndecodableFile {
pub diffs_with_contents: Vec<(DiffWithContents, IdHash)>,
pub diffs_without_contents: Vec<DiffWithoutContents>,
}
/// A file combined with its diffs into sections
#[derive(Debug)]
pub struct Combined {
pub sections: Vec<Section>,
pub max_line_num: usize,
}
#[derive(Debug)]
pub enum DiffWithContents {
Add {
contents: Option<String>,
},
Edit {
line: usize,
deleted: bool,
contents: String,
},
Replacement {
line: usize,
/// Deleted line
change_contents: String,
/// Added lines
replacement_contents: String,
},
// Also present in `DiffWithoutContents` to show that the whole file is
// deleted
Del {
contents: Option<String>,
},
Undel,
}
#[derive(Debug)]
pub enum DiffWithoutContents {
// _________________________________________________________________________
// Cases that never have contents:
Move {
old_path: String,
},
MoveEdge,
Del,
SolveNameConflict,
UnsolveNameConflict,
SolveOrderConflict,
UnsolveOrderConflict,
ResurrectZombines,
AddRoot,
DelRoot,
// _________________________________________________________________________
// Cases that normally have contents, but in these cases the contents are
// not decodable:
Edit {
line: usize,
deleted: bool,
contents: UndecodableContents,
},
Replacement {
line: usize,
/// Deleted line
change_contents: UndecodableContents,
/// Added lines
replacement_contents: UndecodableContents,
},
}
#[derive(Debug)]
pub enum UndecodableContents {
/// Short byte sequence of unknown encoding encoded with base64 for
/// display. Must be shorter than [`crate::repo::MAX_LEN_BASE64_DISPLAY`]
ShortBase64(String),
UnknownEncoding,
}
#[derive(Debug)]
pub enum Section {
Unchanged(Lines),
/// `deleted` and `added` are together because for
/// `ChangedFileDiffWithContents::Replacement` they begin on the same line
/// number
Changed {
deleted: Lines,
added: Lines,
diff_id: IdHash,
},
}
/// INVARIANT: There must be no new-lines in any of the strings, the source
/// string must be split on those.
pub type Lines = Vec<String>;
pub fn contents_to_lines(contents: &str) -> Lines {
contents.split('\n').map(str::to_string).collect()
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Id {
pub diff: repo::ChangedFileDiff,
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct IdRef<'a> {
pub diff: &'a repo::ChangedFileDiff,
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct IdHash(pub AHash);
pub fn id_hash(id: &Id) -> IdHash {
IdHash(hash_one(id))
}
pub fn id_ref_hash(id: &IdRef<'_>) -> IdHash {
IdHash(hash_one(id))
}
pub fn id_parts_hash(diff: &repo::ChangedFileDiff) -> IdHash {
id_ref_hash(&IdRef { diff })
}