devela/num/unit/
traits.rs

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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// devela::num::unit::traits
//
//! Unit prefixes traits.
//
// TOC
// - trait Unit
// - impl Unit for UnitBi, UnitSi.

use super::{UnitBi, UnitSi};
#[cfg(feature = "alloc")]
use crate::data::Vec;

/// Unit prefixes.
///
/// - <https://en.wikipedia.org/wiki/Unit_of_measurement>
pub trait Unit: Sized {
    /// Returns the symbol of the prefix.
    #[must_use]
    fn symbol(&self) -> &str;
    /// Returns the ASCII symbol of the prefix.
    #[must_use]
    fn symbol_ascii(&self) -> &str;
    /// Returns the name of the prefix.
    #[must_use]
    fn name(&self) -> &str;

    /// Returns the multiplication factor for the prefix as an f64.
    #[must_use]
    fn factor(&self) -> f64;
    /// Returns the multiplication factor for the prefix as an i64.
    #[must_use]
    fn factor_i64(&self) -> i64;
    /// Returns the multiplication factor for the prefix as an i128.
    #[must_use]
    fn factor_i128(&self) -> i128;

    /// Returns an iterator in ascending order of magnitude.
    fn asc_iter() -> impl Iterator<Item = Self>;
    /// Returns an iterator in descending order of magnitude.
    fn desc_iter() -> impl Iterator<Item = Self>;

    /// The base value for unit prefixes.
    const BASE: Option<i32> = None;
    /// Returns the exponent corresponding to the unit prefix.
    #[must_use]
    fn exp(&self) -> Option<i32> {
        None
    }

    /// Converts a value from one unit prefix variant to another,
    /// returning the converted value.
    #[must_use]
    fn convert(value: f64, from: Self, to: Self) -> f64;
    /// Converts a value from one prefix to another,
    /// returning the converted value and the remainder.
    #[must_use]
    fn convert_i64(value: i64, from: Self, to: Self) -> (i64, i64);
    /// Converts a value from one prefix to another,
    /// returning the converted value and the remainder.
    #[must_use]
    fn convert_i128(value: i128, from: Self, to: Self) -> (i128, i128);

    /// Reduces the given `value` to the most appropriate prefix as a f64,
    /// returning a tuple of the reduced size and the prefix.
    ///
    /// The input `value` is assumed to be non-negative, and in base units,
    /// meaning it has no prefix applied.
    ///
    /// This method simplifies large numerical values by scaling them down
    /// to the largest appropriate prefix (e.g., Kibi, Mebi, Gibi, etc.).
    #[must_use]
    #[cfg(any(feature = "std", feature = "_float_f64"))]
    fn reduce(value: f64) -> (f64, Self);
    /// Reduces the given value to the most appropriate prefix as a i64,
    /// returning a tuple of the reduced size, the prefix, and the remainder.
    ///
    /// The input `value` is assumed to be non-negative, and in base units,
    /// meaning it has no prefix applied.
    ///
    /// This method simplifies large numerical values by scaling them down
    /// to the largest appropriate prefix (e.g., Kibi, Mebi, Gibi, etc.).
    #[must_use]
    fn reduce_i64(value: i64) -> (i64, Self, i64);
    /// Reduces the given value to the most appropriate prefix as a i128,
    /// returning a tuple of the reduced size, the prefix, and the remainder.
    ///
    /// The input `value` is assumed to be non-negative, and in base units,
    /// meaning it has no prefix applied.
    ///
    /// This method simplifies large numerical values by scaling them down
    /// to the largest appropriate prefix (e.g., Kibi, Mebi, Gibi, etc.).
    #[must_use]
    fn reduce_i128(value: i128) -> (i128, Self, i128);

    /// Reduces the given value to a chain of appropriate prefixes as f64,
    /// stopping when the remainder is less than the given threshold.
    #[must_use]
    #[cfg(any(feature = "std", all(feature = "alloc", feature = "_float_f64")))]
    fn reduce_chain(value: f64, threshold: f64) -> Vec<(f64, Self)>;
    /// Reduces the given value to a chain of appropriate prefixes as i64,
    /// stopping when the remainder is less than the given threshold.
    #[must_use]
    #[cfg(feature = "alloc")]
    fn reduce_chain_i64(value: i64, threshold: i64) -> Vec<(i64, Self)>;
    /// Reduces the given value to a chain of appropriate prefixes as i128,
    /// stopping when the remainder is less than the given threshold.
    #[must_use]
    #[cfg(feature = "alloc")]
    fn reduce_chain_i128(value: i128, threshold: i128) -> Vec<(i128, Self)>;
}

// -----------------------------------------------------------------------------

macro_rules! impl_unit {
    ($($t:ty),+) => { $( impl_unit![@$t]; )+ };
    (@$t:ty) => {
        impl Unit for $t {
            fn symbol(&self) -> &str { self.symbol() }
            fn symbol_ascii(&self) -> &str { self.symbol_ascii() }
            fn name(&self) -> &str { self.name() }

            fn factor(&self) -> f64 { self.factor() }
            fn factor_i64(&self) -> i64 { self.factor_i64() }
            fn factor_i128(&self) -> i128 { self.factor_i128() }

            fn asc_iter() -> impl Iterator<Item = Self> { Self::asc_iter() }
            fn desc_iter() -> impl Iterator<Item = Self> { Self::desc_iter() }

            const BASE: Option<i32> = Some(Self::BASE);
            fn exp(&self) -> Option<i32> { Some(self.exp()) }

            fn convert(value: f64, from: Self, to: Self) -> f64 {
                Self::convert(value, from, to)
            }
            fn convert_i64(value: i64, from: Self, to: Self) -> (i64, i64) {
                Self::convert_i64(value, from, to)
            }
            fn convert_i128(value: i128, from: Self, to: Self) -> (i128, i128) {
                Self::convert_i128(value, from, to)
            }

            #[cfg(any(feature = "std", feature = "_float_f64"))]
            fn reduce(value: f64) -> (f64, Self) { Self::reduce(value) }
            fn reduce_i64(value: i64) -> (i64, Self, i64) { Self::reduce_i64(value) }
            fn reduce_i128(value: i128) -> (i128, Self, i128){ Self::reduce_i128(value) }

            #[cfg(any(feature = "std", all(feature = "alloc", feature = "_float_f64")))]
            fn reduce_chain(value: f64, threshold: f64) -> Vec<(f64, Self)> {
                Self::reduce_chain(value, threshold)
            }
            #[cfg(feature = "alloc")]
            fn reduce_chain_i64(value: i64, threshold: i64) -> Vec<(i64, Self)> {
                Self::reduce_chain_i64(value, threshold)
            }
            #[cfg(feature = "alloc")]
            fn reduce_chain_i128(value: i128, threshold: i128) -> Vec<(i128, Self)> {
                Self::reduce_chain_i128(value, threshold)
            }
        }
    };
}
impl_unit![UnitBi, UnitSi];