use std::cmp::Ordering;
use rustc_span::Span;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub(super) enum Style {
#[default]
Alphabetical,
PrefixThenAlphabetical,
}
pub(super) struct DeriveEntry {
pub(super) final_name: String,
pub(super) span: Span,
}
pub(super) fn desired_order(
style: Style,
prefix: &[String],
entries: &[DeriveEntry],
) -> Vec<usize> {
match style {
Style::Alphabetical => {
let mut indices: Vec<usize> = (0..entries.len()).collect();
indices.sort_by(|left, right| {
ascii_ci_cmp(&entries[*left].final_name, &entries[*right].final_name)
});
indices
}
Style::PrefixThenAlphabetical => {
let mut used = vec![false; entries.len()];
let mut order: Vec<usize> = Vec::with_capacity(entries.len());
for prefix_name in prefix {
for (index, entry) in entries.iter().enumerate() {
if !used[index] && entry.final_name == *prefix_name {
order.push(index);
used[index] = true;
break;
}
}
}
let mut rest: Vec<usize> = (0..entries.len()).filter(|index| !used[*index]).collect();
rest.sort_by(|left, right| {
ascii_ci_cmp(&entries[*left].final_name, &entries[*right].final_name)
});
order.extend(rest);
order
}
}
}
pub(super) fn is_identity(permutation: &[usize]) -> bool {
permutation
.iter()
.enumerate()
.all(|(position, &index)| position == index)
}
fn ascii_ci_cmp(left: &str, right: &str) -> Ordering {
left.bytes()
.map(|byte| byte.to_ascii_lowercase())
.cmp(right.bytes().map(|byte| byte.to_ascii_lowercase()))
}