1use ouisync_macros::api;
2use serde::{Deserialize, Serialize};
3use std::{
4 fmt,
5 ops::{Div, Mul},
6};
7
8#[derive(Default, Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
10#[api]
11pub struct Progress {
12 pub value: u64,
13 pub total: u64,
14}
15
16impl Progress {
17 pub fn ratio(&self) -> f64 {
18 if self.total == 0 {
19 1.0
20 } else {
21 self.value as f64 / self.total as f64
22 }
23 }
24
25 pub fn percent(self) -> Percent {
26 Percent(self)
27 }
28}
29
30impl Mul<u64> for Progress {
31 type Output = Self;
32
33 fn mul(self, rhs: u64) -> Self::Output {
34 Self {
35 value: self.value * rhs,
36 total: self.total * rhs,
37 }
38 }
39}
40
41impl Div<u64> for Progress {
42 type Output = Self;
43
44 fn div(self, rhs: u64) -> Self::Output {
45 Self {
46 value: self.value / rhs,
47 total: self.total / rhs,
48 }
49 }
50}
51
52pub struct Percent(Progress);
54
55impl fmt::Display for Progress {
56 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57 write!(f, "{}/{}", self.value, self.total)
58 }
59}
60
61impl fmt::Display for Percent {
62 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63 let ratio = self.0.ratio();
64 let precision = f.precision().unwrap_or(0);
65
66 write!(f, "{:1.*}%", precision, 100.0 * ratio)
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn format_percent() {
76 assert_eq!(
77 format!(
78 "{}",
79 Progress {
80 value: 0,
81 total: 10
82 }
83 .percent()
84 ),
85 "0%"
86 );
87
88 assert_eq!(
89 format!(
90 "{}",
91 Progress {
92 value: 1,
93 total: 10
94 }
95 .percent()
96 ),
97 "10%"
98 );
99
100 assert_eq!(
101 format!(
102 "{}",
103 Progress {
104 value: 2,
105 total: 10
106 }
107 .percent()
108 ),
109 "20%"
110 );
111
112 assert_eq!(
113 format!(
114 "{}",
115 Progress {
116 value: 10,
117 total: 10
118 }
119 .percent()
120 ),
121 "100%"
122 );
123
124 assert_eq!(
125 format!(
126 "{:.1}",
127 Progress {
128 value: 5,
129 total: 10
130 }
131 .percent()
132 ),
133 "50.0%"
134 );
135
136 assert_eq!(
137 format!(
138 "{:.2}",
139 Progress {
140 value: 5,
141 total: 10
142 }
143 .percent()
144 ),
145 "50.00%"
146 );
147 }
148}