1#[cfg(test)] mod tests;
5
6use std::{fmt, ops::{Add, AddAssign, Mul, MulAssign}};
7
8use num_traits::NumCast;
9
10pub trait Percent {
12 fn percent(self) -> Percentage;
22}
23
24macro_rules! percent_impl {
25 ($($ty:ty)*) => {
26 $(
27 impl Percent for $ty {
28 fn percent(self) -> Percentage {
29 Percentage::new(self)
30 }
31 }
32 )*
33 };
34}
35
36percent_impl!{
37 usize u8 u16 u32 u64 u128
38 isize i8 i16 i32 i64 i128
39 f32 f64
40}
41
42#[derive(Default, Clone, Copy, PartialEq, Debug)]
69#[cfg_attr(feature = "serde_support", derive(serde::Serialize, serde::Deserialize))]
70pub struct Percentage(f32);
71
72impl Percentage {
73 pub fn new<T: NumCast>(value: T) -> Percentage {
75 Self(value.to_f32().unwrap() / 100.0)
76 }
77}
78
79impl fmt::Display for Percentage {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 write!(f, "{}%", self.0*100.0)
82 }
83}
84
85impl Add for Percentage {
86 type Output = Self;
87 fn add(self, rhs: Self) -> Self::Output {
88 Self(self.0 + rhs.0)
89 }
90}
91
92impl AddAssign for Percentage {
93 fn add_assign(&mut self, rhs: Percentage) {
94 *self = *self + rhs;
95 }
96}
97
98impl<T: NumCast> AddAssign<T> for Percentage {
99 fn add_assign(&mut self, rhs: T) {
100 *self = Self(self.0 + rhs.to_f32().unwrap());
101 }
102}
103
104impl Mul for Percentage {
105 type Output = Self;
106 fn mul(self, rhs: Self) -> Self::Output {
107 Self(rhs.0*self.0)
108 }
109}
110
111impl MulAssign for Percentage {
112 fn mul_assign(&mut self, rhs: Self) {
113 *self = *self * rhs;
114 }
115}
116
117macro_rules! ops_percentage_impl {
118 ($($type: ty)*) => {
119 $(
120 impl Add<Percentage> for $type {
121 type Output = Percentage;
122 fn add(self, rhs: Percentage) -> Self::Output {
123 Percentage(rhs.0 + self as f32)
124 }
125 }
126
127 impl Mul<Percentage> for $type {
128 type Output = f32;
129 fn mul(self, rhs: Percentage) -> Self::Output {
130 self as f32 * rhs.0
131 }
132 }
133
134 impl MulAssign<Percentage> for $type {
135 fn mul_assign(&mut self, rhs: Percentage) {
136 *self = (*self * rhs) as $type;
137 }
138 }
139 )*
140 };
141}
142
143ops_percentage_impl!{
144 usize u8 u16 u32 u64 u128
145 isize i8 i16 i32 i64 i128
146 f32 f64
147}