use super::resolve_conflicts::ResolvedEntry;
#[derive(Debug, Clone)]
pub(crate) struct SortResult {
pub vs: Vec<String>,
pub barycenter: Option<f64>,
pub weight: Option<i32>,
}
pub(crate) fn sort(entries: &[ResolvedEntry], bias_right: bool) -> SortResult {
let mut sortable: Vec<&ResolvedEntry> = Vec::new();
let mut unsortable: Vec<&ResolvedEntry> = Vec::new();
for entry in entries {
if entry.barycenter.is_some() {
sortable.push(entry);
} else {
unsortable.push(entry);
}
}
unsortable.sort_by(|a, b| b.i.cmp(&a.i));
sortable.sort_by(|a, b| {
let a_bc = a.barycenter.unwrap();
let b_bc = b.barycenter.unwrap();
if a_bc < b_bc {
return std::cmp::Ordering::Less;
}
if a_bc > b_bc {
return std::cmp::Ordering::Greater;
}
if !bias_right {
a.i.cmp(&b.i)
} else {
b.i.cmp(&a.i)
}
});
let mut vs: Vec<Vec<String>> = Vec::new();
let mut sum = 0.0_f64;
let mut weight = 0_i32;
let mut vs_index: usize = 0;
consume_unsortable(&mut vs, &mut unsortable, &mut vs_index);
for entry in &sortable {
vs_index += entry.vs.len();
vs.push(entry.vs.clone());
sum += entry.barycenter.unwrap() * entry.weight.unwrap() as f64;
weight += entry.weight.unwrap();
consume_unsortable(&mut vs, &mut unsortable, &mut vs_index);
}
let flat: Vec<String> = vs.into_iter().flatten().collect();
let mut result = SortResult {
vs: flat,
barycenter: None,
weight: None,
};
if weight > 0 {
result.barycenter = Some(sum / weight as f64);
result.weight = Some(weight);
}
result
}
fn consume_unsortable(
vs: &mut Vec<Vec<String>>,
unsortable: &mut Vec<&ResolvedEntry>,
index: &mut usize,
) {
while let Some(last) = unsortable.last() {
if last.i <= *index {
let entry = unsortable.pop().unwrap();
vs.push(entry.vs.clone());
*index += 1;
} else {
break;
}
}
}