use super::{FaceInfo, ID, Query, Stretch, Style, Weight};
#[inline(never)]
pub(super) fn find_best_match(candidates: &[(ID, &FaceInfo)], query: &Query) -> Option<ID> {
debug_assert!(!candidates.is_empty());
let mut matching_set: Vec<usize> = (0..candidates.len()).collect();
let matches = matching_set
.iter()
.any(|&index| candidates[index].1.stretch == query.stretch);
let matching_stretch = if matches {
query.stretch
} else if query.stretch <= Stretch::Normal {
let stretch = matching_set
.iter()
.filter(|&&index| candidates[index].1.stretch < query.stretch)
.min_by_key(|&&index| query.stretch.to_number() - candidates[index].1.stretch.to_number());
match stretch {
Some(&matching_index) => candidates[matching_index].1.stretch,
None => {
let matching_index = *matching_set
.iter()
.min_by_key(|&&index| candidates[index].1.stretch.to_number() - query.stretch.to_number())?;
candidates[matching_index].1.stretch
}
}
} else {
let stretch = matching_set
.iter()
.filter(|&&index| candidates[index].1.stretch > query.stretch)
.min_by_key(|&&index| candidates[index].1.stretch.to_number() - query.stretch.to_number());
match stretch {
Some(&matching_index) => candidates[matching_index].1.stretch,
None => {
let matching_index = *matching_set
.iter()
.min_by_key(|&&index| query.stretch.to_number() - candidates[index].1.stretch.to_number())?;
candidates[matching_index].1.stretch
}
}
};
matching_set.retain(|&index| candidates[index].1.stretch == matching_stretch);
let style_preference = match query.style {
Style::Italic => [Style::Italic, Style::Oblique, Style::Normal],
Style::Oblique => [Style::Oblique, Style::Italic, Style::Normal],
Style::Normal => [Style::Normal, Style::Oblique, Style::Italic],
};
let matching_style = *style_preference.iter().find(|&query_style| {
matching_set
.iter()
.any(|&index| candidates[index].1.style == *query_style)
})?;
matching_set.retain(|&index| candidates[index].1.style == matching_style);
let weight = query.weight.0;
let matching_weight = if matching_set.iter().any(|&index| candidates[index].1.weight.0 == weight) {
Weight(weight)
} else if (400..450).contains(&weight) && matching_set.iter().any(|&index| candidates[index].1.weight.0 == 500) {
Weight::MEDIUM
} else if (450..=500).contains(&weight) && matching_set.iter().any(|&index| candidates[index].1.weight.0 == 400) {
Weight::NORMAL
} else if weight <= 500 {
let idx = matching_set
.iter()
.filter(|&&index| candidates[index].1.weight.0 <= weight)
.min_by_key(|&&index| weight - candidates[index].1.weight.0);
match idx {
Some(&matching_index) => candidates[matching_index].1.weight,
None => {
let matching_index = *matching_set
.iter()
.min_by_key(|&&index| candidates[index].1.weight.0 - weight)?;
candidates[matching_index].1.weight
}
}
} else {
let idx = matching_set
.iter()
.filter(|&&index| candidates[index].1.weight.0 >= weight)
.min_by_key(|&&index| candidates[index].1.weight.0 - weight);
match idx {
Some(&matching_index) => candidates[matching_index].1.weight,
None => {
let matching_index = *matching_set
.iter()
.min_by_key(|&&index| weight - candidates[index].1.weight.0)?;
candidates[matching_index].1.weight
}
}
};
matching_set.retain(|&index| candidates[index].1.weight == matching_weight);
matching_set.into_iter().next().map(|index| candidates[index].0)
}