1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
// Licensed under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0 or the MIT license
// http://opensource.org/licenses/MIT, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use ord_subset_trait::*;
use ord_var::*;

/////////////////////////////////////////////////////////////////////
pub trait OrdSubsetIterExt: Iterator //where Self::Item: OrdSubset
{
    /// Consumes the entire iterator to return the maximum element.
    /// Values outside the ordered subset as given by `.is_outside_order()` are ignored.
    ///
    /// Returns the last element if the comparison determines multiple elements to be equally maximum.
    ///
    /// # Example
    ///
    /// ```
    /// use ord_subset::OrdSubsetIterExt;
    ///
    /// let vec = vec![2.0, 3.0, 5.0, std::f64::NAN];
    /// let max = vec.iter().ord_subset_max().unwrap();
    /// assert_eq!(&5.0, max);
    /// ```
    #[inline]
    fn ord_subset_max(self) -> Option<Self::Item>
    where
        Self: Sized,
        Self::Item: OrdSubset,
    {
        self.filter_map(OrdVar::new_checked)
            .max()
            .map(OrdVar::into_inner) // Option<OrdVar<Item>> => Option<Item>
    }

    /// Consumes the entire iterator to return the minimum element.
    /// Values outside the ordered subset as given by `.is_outside_order()` are ignored.
    ///
    /// Returns the first element if the comparison determines multiple elements to be equally minimum.
    ///
    /// # Example
    ///
    /// ```
    /// use ord_subset::OrdSubsetIterExt;
    ///
    /// let vec = vec![2.0, 3.0, 5.0, std::f64::NAN];
    /// let min = vec.iter().ord_subset_min().unwrap();
    /// assert_eq!(&2.0, min);
    /// ```
    #[inline]
    fn ord_subset_min(self) -> Option<Self::Item>
    where
        Self: Sized,
        Self::Item: OrdSubset,
    {
        self.filter_map(OrdVar::new_checked)
            .min()
            .map(OrdVar::into_inner) // Option<OrdVar<Item>> => Option<Item>
    }

    /// Returns the element that gives the minimum value from the specified function.
    /// Values outside the ordered subset as given by `.is_outside_order()` on the mapped value are ignored.
    ///
    /// Returns the first element if the comparison determines multiple elements to be equally minimum.
    ///
    /// # Example
    ///
    /// ```
    /// extern crate ord_subset;
    /// use ord_subset::OrdSubsetIterExt;
    ///
    /// fn main() {
    /// 	let vec = vec![2.0, 3.0, 5.0, std::f64::NAN];
    /// 	let min_by = vec.iter().ord_subset_min_by_key(|num| num.recip()).unwrap();
    /// 	assert_eq!(&5.0, min_by);
    /// }
    /// ```
    #[inline]
    fn ord_subset_min_by_key<F, B>(self, mut f: F) -> Option<Self::Item>
    where
        F: FnMut(&Self::Item) -> B,
        B: OrdSubset,
        Self: Sized,
    {
        // Ok < Err, always
        self.min_by_key(|it| OrdVar::new_checked(f(it)).ok_or(()))
    }

    /// Returns the element that gives the maximum value from the specified function.
    /// Values outside the ordered subset as given by `.is_outside_order()` on the mapped value are ignored.
    ///
    /// Returns the last element if the comparison determines multiple elements to be equally maximum.
    #[inline]
    fn ord_subset_max_by_key<F, B>(self, mut f: F) -> Option<Self::Item>
    where
        F: FnMut(&Self::Item) -> B,
        B: OrdSubset,
        Self: Sized,
    {
        // Some > None, always
        self.max_by_key(|it| OrdVar::new_checked(f(it)))
    }
}

impl<T: ?Sized + Iterator> OrdSubsetIterExt for T {}