use libpijul::HashMap;
use crate::{diff, file};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Pick {
Include,
Exclude,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum PickSet {
#[default]
Include,
Exclude,
Partial,
}
#[derive(Clone, Debug, Default)]
pub struct State {
pub overall: PickSet,
pub files: HashMap<file::Path, PickSet>,
pub changes: HashMap<file::Path, PartialFile>,
}
#[derive(Clone, Debug, Default)]
pub struct PartialFile {
pub changes: HashMap<diff::IdHash, Pick>,
}
pub fn default_pick_set(state: &State) -> PickSet {
match default_pick(state) {
Pick::Include => PickSet::Include,
Pick::Exclude => PickSet::Exclude,
}
}
pub fn default_pick(state: &State) -> Pick {
let State {
overall,
files,
changes: _,
} = state;
if matches!(overall, PickSet::Partial)
|| files
.values()
.any(|pick| matches!(pick, PickSet::Partial | PickSet::Exclude))
{
Pick::Exclude
} else {
Pick::Include
}
}
pub fn determine_file(state: &State, file: &file::Path) -> PickSet {
match state.overall {
PickSet::Include => PickSet::Include,
PickSet::Exclude => PickSet::Exclude,
PickSet::Partial => {
if let Some(pick) = state.files.get(file) {
*pick
} else if file_has_any_partial_change(file, &state.changes) {
PickSet::Partial
} else {
default_pick_set(state)
}
}
}
}
pub fn determine_change(
file: &file::Path,
diff_id: diff::IdHash,
state: &State,
) -> Pick {
match state.overall {
PickSet::Include => return Pick::Include,
PickSet::Exclude => return Pick::Exclude,
PickSet::Partial => {}
}
if let Some(pick) = state.files.get(file) {
match pick {
PickSet::Include => return Pick::Include,
PickSet::Exclude => return Pick::Exclude,
PickSet::Partial => {}
}
}
let explicit = state
.changes
.get(file)
.and_then(|file| file.changes.get(&diff_id))
.copied();
explicit.unwrap_or_else(|| default_pick(state))
}
pub fn file_has_any_partial_change(
file: &file::Path,
changes: &HashMap<file::Path, PartialFile>,
) -> bool {
let (mut has_include, mut has_exclude) = (false, false);
changes
.get(file)
.map(|file| {
file.changes.values().any(|pick| {
has_exclude |= matches!(pick, Pick::Exclude);
has_include |= matches!(pick, Pick::Include);
has_include && has_exclude
})
})
.unwrap_or_default()
}