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