#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#[derive(Debug, Copy, Clone)]
pub struct Max<Item> {
item: Option<Item>,
}
#[derive(Debug, Copy, Clone)]
pub struct Min<Item> {
item: Option<Item>,
}
macro_rules! impl_minmax {
($name: ident, $cmpval: expr) => {
impl<Item> $name<Item> {
pub fn new(initial: Item) -> Self {
Self {
item: Some(initial),
}
}
pub fn into_inner(self) -> Option<Item> {
self.item
}
pub fn as_ref(&self) -> Option<&Item> {
self.item.as_ref()
}
pub fn reduce(&mut self, item: Item)
where
Item: PartialOrd,
{
if self.item.is_none()
|| self
.item
.as_ref()
.map(|i| item.partial_cmp(i) == Some($cmpval))
== Some(true)
{
self.item = Some(item);
}
}
pub fn eval(&mut self, item: Item)
where
Item: PartialOrd,
{
self.reduce(item)
}
}
impl<Item> From<Item> for $name<Item> {
fn from(item: Item) -> Self {
Self::new(item)
}
}
impl<Item> Extend<Item> for $name<Item>
where
Item: PartialOrd,
{
fn extend<It: IntoIterator<Item = Item>>(&mut self, iter: It) {
iter.into_iter().for_each(|i| self.reduce(i));
}
}
impl<Item> Default for $name<Item> {
fn default() -> Self {
Self { item: None }
}
}
impl<Item> std::iter::FromIterator<Item> for $name<Item>
where
Item: PartialOrd,
{
fn from_iter<It: IntoIterator<Item = Item>>(iter: It) -> Self {
let mut autofolder = Self::default();
autofolder.extend(iter);
autofolder
}
}
};
}
impl_minmax!(Max, std::cmp::Ordering::Greater);
impl_minmax!(Min, std::cmp::Ordering::Less);
#[derive(Debug, Copy, Clone)]
pub struct MinMax<Item> {
min: Option<Item>,
max: Option<Item>,
}
impl<Item> MinMax<Item> {
pub fn new(initial: Item) -> Self {
Self {
min: Some(initial),
max: None,
}
}
pub fn into_inner(self) -> (Option<Item>, Option<Item>) {
(self.min, self.max)
}
pub fn into_inners(self) -> Option<(Item, Item)> {
match (self.min, self.max) {
(None, _) => None,
(_, None) => None,
(Some(min), Some(max)) => Some((min, max)),
}
}
pub fn into_inner_unwrap(self) -> (Item, Item) {
(self.min.unwrap(), self.max.unwrap())
}
pub fn as_ref(&self) -> (Option<&Item>, Option<&Item>) {
(self.min.as_ref(), self.max.as_ref())
}
pub fn as_refs(&self) -> Option<(&Item, &Item)> {
match (&self.min, &self.max) {
(None, _) => None,
(_, None) => None,
(Some(min), Some(max)) => Some((min, max)),
}
}
pub fn min_as_ref(&self) -> Option<&Item> {
self.min.as_ref()
}
pub fn max_as_ref(&self) -> Option<&Item> {
self.max.as_ref()
}
pub fn reduce(&mut self, item: Item)
where
Item: PartialOrd,
{
let oldmin_opt = std::mem::take(&mut self.min);
if let Some(oldmin) = oldmin_opt {
let cmpmin = item.partial_cmp(&oldmin);
if cmpmin == Some(std::cmp::Ordering::Less) {
if self.max.is_none() {
self.max = Some(oldmin);
}
self.min = Some(item);
} else {
self.min = Some(oldmin);
let oldmax_opt = std::mem::take(&mut self.max);
if let Some(oldmax) = oldmax_opt {
if item.partial_cmp(&oldmax) == Some(std::cmp::Ordering::Greater) {
self.max = Some(item);
} else {
self.max = Some(oldmax);
}
} else if cmpmin == Some(std::cmp::Ordering::Greater) {
self.max = Some(item);
} else {
};
}
} else {
self.min = Some(item);
};
}
pub fn eval(&mut self, item: Item)
where
Item: PartialOrd,
{
self.reduce(item)
}
}
impl<Item> From<Item> for MinMax<Item> {
fn from(item: Item) -> Self {
Self::new(item)
}
}
impl<Item> Extend<Item> for MinMax<Item>
where
Item: PartialOrd,
{
fn extend<It: IntoIterator<Item = Item>>(&mut self, iter: It) {
iter.into_iter().for_each(|i| self.reduce(i));
}
}
impl<Item> Default for MinMax<Item> {
fn default() -> Self {
Self {
min: None,
max: None,
}
}
}
impl<Item> std::iter::FromIterator<Item> for MinMax<Item>
where
Item: PartialOrd,
{
fn from_iter<It: IntoIterator<Item = Item>>(iter: It) -> Self {
let mut autofolder = Self::default();
autofolder.extend(iter);
autofolder
}
}