use std::{cmp::Ordering, fmt::Debug, ops::ControlFlow};
use crate::{
collector::{Collector, CollectorBase, assert_collector},
iter::Fold,
};
#[derive(Clone)]
pub struct MinBy<T, F> {
min: Option<T>,
f: F,
}
impl<T, F> MinBy<T, F>
where
F: FnMut(&T, &T) -> Ordering,
{
#[deprecated(since = "0.3.0", note = "Use `Min::by`")]
#[inline]
pub const fn new(f: F) -> Self {
assert_collector(Self { min: None, f })
}
}
impl<T, F> CollectorBase for MinBy<T, F> {
type Output = Option<T>;
#[inline]
fn finish(self) -> Self::Output {
self.min
}
}
impl<T, F> Collector<T> for MinBy<T, F>
where
F: FnMut(&T, &T) -> Ordering,
{
#[inline]
fn collect(&mut self, item: T) -> ControlFlow<()> {
match self.min {
None => self.min = Some(item),
Some(ref mut min) => min_assign_by(min, item, &mut self.f),
}
ControlFlow::Continue(())
}
fn collect_many(&mut self, items: impl IntoIterator<Item = T>) -> ControlFlow<()> {
match self.min {
None => self.min = items.into_iter().min_by(&mut self.f),
Some(ref mut min) => {
items.into_iter().for_each({
let mut f = &mut self.f;
move |item| {
min_assign_by(min, item, &mut f);
}
});
}
};
ControlFlow::Continue(())
}
fn collect_then_finish(mut self, items: impl IntoIterator<Item = T>) -> Self::Output {
match self.min {
None => items.into_iter().min_by(self.f),
Some(min) => Some(
Fold::new(min, move |min, item| min_assign_by(min, item, &mut self.f))
.collect_then_finish(items),
),
}
}
}
impl<T: Debug, F> Debug for MinBy<T, F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MinBy").field("min", &self.min).finish()
}
}
fn min_assign_by<T, F>(min: &mut T, value: T, compare: F)
where
F: FnOnce(&T, &T) -> Ordering,
{
if compare(min, &value).is_le() {
} else {
*min = value;
}
}