use {
crate::{
Comparator,
internal::CallbackMetadata,
macros::impl_common_name_methods,
},
std::cmp::Ordering,
std::fmt,
};
type BoxComparatorFn<T> = Box<dyn Fn(&T, &T) -> Ordering>;
#[must_use = "callback wrappers do nothing unless stored or invoked"]
pub struct BoxComparator<T> {
pub(super) function: BoxComparatorFn<T>,
pub(super) metadata: CallbackMetadata,
}
impl<T> BoxComparator<T> {
#[inline]
pub fn new<F>(source: F) -> Self
where
F: Comparator<T> + 'static,
{
Self {
function: Box::new(move |left: &T, right: &T| {
source.compare(left, right)
}),
metadata: CallbackMetadata::unnamed(),
}
}
#[inline]
pub fn new_with_name<F>(name: &str, source: F) -> Self
where
F: Comparator<T> + 'static,
{
Self {
function: Box::new(move |left: &T, right: &T| {
source.compare(left, right)
}),
metadata: CallbackMetadata::named(name),
}
}
#[inline]
pub fn new_with_optional_name<F>(source: F, name: Option<String>) -> Self
where
F: Comparator<T> + 'static,
{
Self {
function: Box::new(move |left: &T, right: &T| {
source.compare(left, right)
}),
metadata: CallbackMetadata::from_optional_name(name),
}
}
#[inline]
pub(crate) fn new_with_metadata<F>(
source: F,
metadata: CallbackMetadata,
) -> Self
where
F: Comparator<T> + 'static,
{
Self {
function: Box::new(move |left: &T, right: &T| {
source.compare(left, right)
}),
metadata,
}
}
#[inline]
pub fn comparing<K, F>(key_fn: F) -> Self
where
K: Ord,
F: Fn(&T) -> &K + 'static,
{
BoxComparator::new(move |a: &T, b: &T| key_fn(a).cmp(key_fn(b)))
}
impl_common_name_methods!("comparator");
#[inline]
pub fn reversed(self) -> Self
where
T: 'static,
{
let metadata = self.metadata;
let function = self.function;
BoxComparator::new_with_metadata(
move |a: &T, b: &T| function(b, a),
metadata,
)
}
#[inline]
pub fn then_comparing<C>(self, other: C) -> Self
where
T: 'static,
C: Comparator<T> + 'static,
{
BoxComparator::new(move |a: &T, b: &T| match (self.function)(a, b) {
Ordering::Equal => other.compare(a, b),
ord => ord,
})
}
#[must_use = "the returned comparator closure should be stored or invoked"]
#[inline(always)]
pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
move |a: &T, b: &T| (self.function)(a, b)
}
}
impl<T> Comparator<T> for BoxComparator<T> {
#[inline(always)]
fn compare(&self, a: &T, b: &T) -> Ordering {
(self.function)(a, b)
}
}
impl<T> fmt::Debug for BoxComparator<T> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("BoxComparator")
.field("name", &self.metadata.name())
.finish()
}
}
impl<T> fmt::Display for BoxComparator<T> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.metadata.name() {
Some(name) => write!(formatter, "BoxComparator({name})"),
None => formatter.write_str("BoxComparator"),
}
}
}