min_max/lib.rs
1//! # **min-max**: `max!` and `min!` macros for Rust
2//!
3//! [](https://crates.io/crates/min-max)
4//! [](https://crates.io/crates/min-max)
5//! [](https://crates.io/crates/min-max)
6//!
7//! ## Why?
8//!
9//! Sometimes you want to find the maximum of a bunch of **scalars**. Usually you would write something like `max(x1, max(x2, max(x3, x4)))`. The `max!` macro provided by this crate simplifies that to `max!(x1, x2, x3, x4)`. (Note, for an **iterable** data structure, you would use `xx.iter().max()`).
10//!
11//! ## Usage
12//!
13//! Add this to your `Cargo.toml`:
14//!
15//! ```toml
16//! min-max = "0.1"
17//! ```
18//!
19//! Then, for example:
20//!
21//! ```rust
22//! use min_max::*;
23//!
24//! fn main() {
25//! let max = max!(1, 5, 7, 2, 4, 9, 3);
26//! assert_eq!(max, 9);
27//! let min = min!(1, 5, 7, 2, 4, 9, 3);
28//! assert_eq!(min, 1);
29//! let min_max = min_max!(1, 5, 7, 2, 4, 9, 3);
30//! assert_eq!(min_max, (min, max));
31//! }
32//! ```
33//!
34//! ### Does it work on floats?
35//!
36//! Yep. But you need to use `max_partial!`/`min_partial!`
37//!
38//! ```rust
39//! use min_max::*;
40//!
41//! fn main() {
42//! let partial_max = max_partial!(1.8f64, 5.8, 7.8, 2.8, 4.8, 9.8, 3.8);
43//! assert!((9.8 - partial_max).abs() < 1e-5);
44//! let partial_min = min_partial!(1.8f64, 5.8, 7.8, 2.8, 4.8, 9.8, 3.8);
45//! assert!((1.8 - partial_min).abs() < 1e-5);
46//! }
47//! ```
48//!
49//! ### What about `NaN`?
50//!
51//! Do not use when your data contains `NaN`. When `NaN` is at the end, `NaN` is returned. Otherwise, the min/max excluding `NaN` is returned.
52//!
53//! ```rust
54//! use min_max::*;
55//!
56//! fn main() {
57//! let partial_max = max_partial!(1.8, 5.8, f64::NAN, 2.8, 4.8, 9.8, 3.8);
58//! assert!((9.8 - partial_max).abs() < 1e-5);
59//! let partial_max = max_partial!(1.8, 5.8, 2.8, 4.8, 9.8, 3.8, f64::NAN);
60//! assert!(partial_max.is_nan());
61//! let partial_min = min_partial!(1.8, 5.8, f64::NAN, 2.8, 4.8, 9.8, 3.8);
62//! assert!((1.8 - partial_min).abs() < 1e-5);
63//! let partial_min = max_partial!(1.8, 5.8, 2.8, 4.8, 9.8, 3.8, f64::NAN);
64//! assert!(partial_min.is_nan());
65//! }
66//! ```
67//!
68//! ### Can I use custom types?
69//!
70//! Sure, why not?
71//!
72//! ```rust
73//! use min_max::*;
74//!
75//! #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Copy)]
76//! struct Point {
77//! x: u16,
78//! y: u16,
79//! }
80//!
81//! fn main() {
82//! let a = Point { x: 5, y: 8 };
83//! let b = Point { x: 10, y: 92 };
84//! let c = Point { x: 0, y: 3 };
85//! let max = max!(a, b, c);
86//! assert_eq!(max, b);
87//! }
88//! ```
89//!
90//! ## What's going on under the hood?
91//!
92//! Well, `max!(x1, x2, x3)` expands to:
93//!
94//! ```ignore
95//! std::cmp::max(x1, std::cmp::max(x2, std::cmp::max(x3)))
96//! ```
97//!
98//! and so on. `min!` works similarly, but with `std::cmp::min`.
99//!
100//! `min_partial!` and `max_partial` uses the `min` and `max` functions from the [`partial-min-max` crate](https://crates.io/crates/partial-min-max).
101
102pub use partial_min_max::{max, min};
103
104/// Returns the maximum element of the arguments.
105#[macro_export]
106macro_rules! max {
107 ($x:expr) => ( $x );
108 ($x:expr, $($xs:expr),+) => {
109 std::cmp::max($x, max!( $($xs),+ ))
110 };
111}
112
113/// Returns the minimum element of the arguments.
114#[macro_export]
115macro_rules! min {
116 ($x:expr) => ( $x );
117 ($x:expr, $($xs:expr),+) => {
118 std::cmp::min($x, min!( $($xs),+ ))
119 };
120}
121
122/// Returns the minimum and maximum element of the arguments.
123#[macro_export]
124macro_rules! min_max {
125 ($x:expr) => ( ($x, $x) );
126 ($($xs:expr),+) => {
127 (min!( $($xs),+ ), max!( $($xs),+ ))
128 };
129}
130
131/// Returns the maximum element of the arguments. Uses [`partial_min_max::max`](https://docs.rs/partial-min-max/0.4.0/partial_min_max/fn.max.html) for comparison.
132#[macro_export]
133macro_rules! max_partial {
134 ($x:expr) => ( $x );
135 ($x:expr, $($xs:expr),+) => {
136 max($x, max_partial!( $($xs),+ ))
137 };
138}
139
140/// Returns the maximum element of the arguments. Uses [`partial_min_max::min`](https://docs.rs/partial-min-max/0.4.0/partial_min_max/fn.min.html) for comparison.
141#[macro_export]
142macro_rules! min_partial {
143 ($x:expr) => ( $x );
144 ($x:expr, $($xs:expr),+) => {
145 min($x, min_partial!( $($xs),+ ))
146 };
147}
148
149/// Returns the minimum and maximum element of the arguments. Uses [`partial_min_max::min`](https://docs.rs/partial-min-max/0.4.0/partial_min_max/fn.min.html) for comparison.
150#[macro_export]
151macro_rules! min_max_partial {
152 ($x:expr) => ( ($x, $x) );
153 ($($xs:expr),+) => {
154 (min_partial!( $($xs),+ ), max_partial!( $($xs),+ ))
155 };
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161 #[test]
162 fn test_int() {
163 let max = max!(1, 5, 7, 2, 4, 9, 3);
164 assert_eq!(max, 9);
165 let min = min!(1, 5, 7, 2, 4, 9, 3);
166 assert_eq!(min, 1);
167 let min_max = min_max!(1, 5, 7, 2, 4, 9, 3);
168 assert_eq!(min_max, (min, max));
169 }
170
171 #[test]
172 fn test_float() {
173 let partial_max = max_partial!(1.8f64, 5.8, 7.8, 2.8, 4.8, 9.8, 3.8);
174 assert!((9.8 - partial_max).abs() < 1e-5);
175 let partial_min = min_partial!(1.8f64, 5.8, 7.8, 2.8, 4.8, 9.8, 3.8);
176 assert!((1.8 - partial_min).abs() < 1e-5);
177 }
178
179 #[test]
180 fn test_struct() {
181 #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Copy)]
182 struct Point {
183 x: u16,
184 y: u16,
185 }
186
187 let a = Point { x: 5, y: 8 };
188 let b = Point { x: 10, y: 92 };
189 let c = Point { x: 0, y: 3 };
190 let max = max!(a, b, c);
191 assert_eq!(max, b);
192 }
193}