ouisync/
progress.rs

1use ouisync_macros::api;
2use serde::{Deserialize, Serialize};
3use std::{
4    fmt,
5    ops::{Div, Mul},
6};
7
8/// Progress of a task.
9#[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
52/// Percentage formatting of `Progress`.
53pub 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}