use {
crate::{
Comparator,
internal::CallbackMetadata,
macros::impl_common_name_methods,
},
std::cmp::Ordering,
std::fmt,
std::rc::Rc,
};
type RcComparatorFn<T> = Rc<dyn Fn(&T, &T) -> Ordering>;
#[derive(Clone)]
#[must_use = "callback wrappers do nothing unless stored or invoked"]
pub struct RcComparator<T> {
pub(super) function: RcComparatorFn<T>,
pub(super) metadata: CallbackMetadata,
}
impl<T> RcComparator<T> {
#[inline]
pub fn new<F>(source: F) -> Self
where
F: Comparator<T> + 'static,
{
Self {
function: Rc::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: Rc::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: Rc::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: Rc::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,
{
RcComparator::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 self_fn = self.function.clone();
RcComparator::new_with_metadata(
move |a: &T, b: &T| self_fn(b, a),
self.metadata.clone(),
)
}
#[inline]
pub fn then_comparing<C>(&self, other: C) -> Self
where
T: 'static,
C: Comparator<T> + 'static,
{
let first = self.function.clone();
RcComparator::new(move |a: &T, b: &T| match first(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 RcComparator<T> {
#[inline(always)]
fn compare(&self, a: &T, b: &T) -> Ordering {
(self.function)(a, b)
}
}
impl<T> fmt::Debug for RcComparator<T> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("RcComparator")
.field("name", &self.metadata.name())
.finish()
}
}
impl<T> fmt::Display for RcComparator<T> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.metadata.name() {
Some(name) => write!(formatter, "RcComparator({name})"),
None => formatter.write_str("RcComparator"),
}
}
}