1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4
5const WIDTH: [(u32, u8); 38] = [
6 (126, 1),
7 (159, 0),
8 (687, 1),
9 (710, 0),
10 (711, 1),
11 (727, 0),
12 (733, 1),
13 (879, 0),
14 (1154, 1),
15 (1161, 0),
16 (4347, 1),
17 (4447, 2),
18 (7467, 1),
19 (7521, 0),
20 (8369, 1),
21 (8426, 0),
22 (9000, 1),
23 (9002, 2),
24 (11021, 1),
25 (12350, 2),
26 (12351, 1),
27 (12438, 2),
28 (12442, 0),
29 (19893, 2),
30 (19967, 1),
31 (55203, 2),
32 (63743, 1),
33 (64106, 2),
34 (65039, 1),
35 (65059, 0),
36 (65131, 2),
37 (65279, 1),
38 (65376, 2),
39 (65500, 1),
40 (65510, 2),
41 (120831, 1),
42 (262141, 2),
43 (1114109, 1),
44];
45
46fn get_width(o: u32) -> u8 {
47 if o == 0xE || o == 0xF {
48 return 0;
49 }
50 for (num, wid) in WIDTH {
51 if o <= num {
52 return wid;
53 }
54 }
55 1
56}
57
58pub fn justify_name(name: &str, length: u8, left_right: bool) -> String {
59 let mut name_width = 0;
60 let mut justified_name = String::new();
61
62 for c in name.chars() {
63 let w = get_width(c as u32);
64 if name_width + w < length {
65 name_width += w;
66 justified_name.push(c);
67 }
68 }
69
70 if name_width < length {
71 let space_count = length - name_width;
72 let spaces = " ".repeat(space_count as usize);
73 if left_right {
74 justified_name += spaces.as_str();
75 } else {
76 justified_name = spaces + &justified_name;
77 }
78 }
79 justified_name
80}
81
82#[derive(Serialize, Deserialize)]
83pub struct SpeedTestResult {
84 #[serde(serialize_with = "serialize_f64")]
85 upload: f64,
86 upload_status: String,
87 #[serde(serialize_with = "serialize_f64")]
88 download: f64,
89 download_status: String,
90 #[serde(serialize_with = "serialize_f64")]
91 latency: f64,
92 #[serde(serialize_with = "serialize_f64")]
93 jitter: f64,
94}
95
96fn serialize_f64<S>(x: &f64, serializer: S) -> Result<S::Ok, S::Error>
97where
98 S: serde::Serializer,
99{
100 let s = format!("{:.1}", x);
101 serializer.serialize_str(&s)
102}
103
104impl SpeedTestResult {
105 pub fn build(
106 upload: f64,
107 upload_status: String,
108 download: f64,
109 download_status: String,
110 latency: f64,
111 jitter: f64,
112 ) -> SpeedTestResult {
113 return SpeedTestResult {
114 upload,
115 upload_status,
116 download,
117 download_status,
118 latency,
119 jitter,
120 };
121 }
122
123 pub fn text(&self) -> String {
124 let upload = justify_name(&format!("{:.1}", &self.upload), 9, false);
125 let upload_status = justify_name(&self.upload_status, 5, false);
126 let download = justify_name(&format!("{:.1}", &self.download), 9, false);
127 let download_status = justify_name(&self.download_status, 5, false);
128 let latency = justify_name(&format!("{:.1}", &self.latency), 7, false);
129 let jitter = justify_name(&format!("{:.1}", &self.jitter), 7, false);
130
131 format!("{upload},{upload_status},{download},{download_status},{latency},{jitter}")
132 }
133}
134
135impl fmt::Display for SpeedTestResult {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 write!(
138 f,
139 "Upload {:.1}Mbps {}, Download: {:.1}Mbps {}, Latency {:.1}, Jitter {:.1}",
140 self.upload,
141 self.upload_status,
142 self.download,
143 self.download_status,
144 self.latency,
145 self.jitter
146 )
147 }
148}