core/
utils.rs

1// Copyright (C) 2017 Steve Sprang
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16use std::cmp;
17use num_traits::Float;
18
19/// Constrain a value within a minimum and maximum range (inclusive).
20pub fn clamp<T: Ord> (value: T, (min, max): (T, T)) -> T {
21    cmp::min(cmp::max(value, min), max)
22}
23
24/// Constrain a float value within a minimum and maximum range (inclusive).
25pub fn clamp_float<F: Float>(value: F, (min, max): (F, F)) -> F {
26    F::min(F::max(value, min), max)
27}
28
29/// Returns a string representing `i` with thousands separated by underscores.
30pub fn pretty_print(mut i: u64) -> String {
31    let mut result: String = String::new();
32    let separator = '_';
33
34    // do once outside the loop to handle 0
35    let mut chunks = vec![i % 1000];
36    i /= 1000;
37
38    while i != 0 {
39        chunks.push(i % 1000);
40        i /= 1000;
41    }
42
43    for (ix, n) in chunks.iter().rev().enumerate() {
44        let digits = if ix == 0 { n.to_string() } else { format!("{:03}", n) };
45        result.push_str(&digits);
46
47        if ix + 1 != chunks.len() {
48            result.push(separator);
49        }
50    }
51
52    result
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    #[test]
60    fn check_pretty_print() {
61        assert_eq!(&pretty_print(0), "0");
62        assert_eq!(&pretty_print(512), "512");
63        assert_eq!(&pretty_print(1024), "1_024");
64        assert_eq!(&pretty_print(16777216), "16_777_216");
65    }
66
67    #[test]
68    fn check_clamp() {
69        let range = (0, 255);
70        assert_eq!(clamp( -1, range),   0);
71        assert_eq!(clamp(100, range), 100);
72        assert_eq!(clamp(256, range), 255);
73
74        let range = (0.0, 1.0);
75        assert_eq!(clamp_float(-1.0, range), 0.0);
76        assert_eq!(clamp_float( 0.5, range), 0.5);
77        assert_eq!(clamp_float( 2.0, range), 1.0);
78    }
79}