1use alloc::format;
49use core::{cmp, fmt};
50
51#[derive(Debug)]
54pub struct InformantLine<'a> {
55 pub enable_colors: bool,
60 pub chain_name: &'a str,
62 pub relay_chain: Option<RelayChain<'a>>,
64 pub max_line_width: u32,
66 pub num_peers: u64,
68 pub num_network_connections: u64,
70 pub network_known_best: Option<u64>,
72 pub best_number: u64,
74 pub best_hash: &'a [u8],
76 pub finalized_number: u64,
78 pub finalized_hash: &'a [u8],
80}
81
82#[derive(Debug)]
84pub struct RelayChain<'a> {
85 pub chain_name: &'a str,
87 pub best_number: u64,
89}
90
91impl<'a> fmt::Display for InformantLine<'a> {
92 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93 let cyan = if self.enable_colors { "\x1b[36m" } else { "" };
98 let white_bold = if self.enable_colors { "\x1b[1;37m" } else { "" };
99 let light_gray = if self.enable_colors { "\x1b[90m" } else { "" };
100 let reset = if self.enable_colors { "\x1b[0m" } else { "" };
101
102 let (header, header_len) = if let Some(relay_chain) = &self.relay_chain {
103 let header = format!(
104 " {cyan}{chain_name}{reset} {white_bold}{local_best:<10}{reset} {light_gray}({relay_chain_name} {relay_best}){reset} [",
105 cyan = cyan,
106 reset = reset,
107 white_bold = white_bold,
108 light_gray = light_gray,
109 chain_name = self.chain_name,
110 relay_chain_name = relay_chain.chain_name,
111 local_best = BlockNumberDisplay(self.best_number),
112 relay_best = BlockNumberDisplay(relay_chain.best_number),
113 );
114
115 let header_len = self.chain_name.chars().count() + relay_chain.chain_name.len() + 29; (header, header_len)
117 } else {
118 let header = format!(
119 " {cyan}{chain_name}{reset} {white_bold}{local_best:<10}{reset} [",
120 cyan = cyan,
121 reset = reset,
122 white_bold = white_bold,
123 chain_name = self.chain_name,
124 local_best = BlockNumberDisplay(self.best_number),
125 );
126
127 let header_len = self.chain_name.chars().count() + 19; (header, header_len)
129 };
130
131 let trailer = format!(
133 "] {white_bold}{network_best}{reset} (🔗{white_bold}{peers:>3}{reset}) (🌐{white_bold}{connec:>4}{reset}) ",
134 network_best = self
135 .network_known_best
136 .map(BlockNumberDisplay)
137 .map_or(either::Right("?"), either::Left),
138 peers = self.num_network_connections,
139 connec = self.num_network_connections,
140 white_bold = white_bold,
141 reset = reset,
142 );
143 let trailer_len = format!(
144 "] {network_best} ( {peers:>3}) ( {connec:>4}) ",
145 network_best = self
146 .network_known_best
147 .map(BlockNumberDisplay)
148 .map(either::Left)
149 .unwrap_or(either::Right("?")),
150 peers = self.num_network_connections,
151 connec = self.num_network_connections,
152 )
153 .len();
154
155 let bar_width = self
156 .max_line_width
157 .saturating_sub(u32::try_from(header_len).unwrap())
158 .saturating_sub(u32::try_from(trailer_len).unwrap());
159
160 let actual_network_best = cmp::max(self.network_known_best.unwrap_or(0), self.best_number);
161 assert!(self.best_number <= actual_network_best);
162 let bar_done_width = u128::from(self.best_number)
163 .checked_mul(u128::from(bar_width))
164 .unwrap()
165 .checked_div(u128::from(actual_network_best))
166 .unwrap_or(0); let bar_done_width = u32::try_from(bar_done_width).unwrap();
168
169 let done_bar1 = "=".repeat(usize::try_from(bar_done_width.saturating_sub(1)).unwrap());
170 let done_bar2 = if bar_done_width == bar_width {
171 '='
172 } else {
173 '>'
174 };
175 let todo_bar = " ".repeat(
176 usize::try_from(
177 bar_width
178 .checked_sub(bar_done_width.saturating_sub(1).saturating_add(1))
179 .unwrap(),
180 )
181 .unwrap(),
182 );
183 assert_eq!(
184 done_bar1.len() + 1 + todo_bar.len(),
185 usize::try_from(bar_width).unwrap()
186 );
187
188 write!(f, "{header}{done_bar1}{done_bar2}{todo_bar}{trailer}")
189 }
190}
191
192pub struct HashDisplay<'a>(pub &'a [u8]);
194
195impl<'a> fmt::Display for HashDisplay<'a> {
196 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
197 write!(f, "0x")?;
198 if self.0.len() >= 2 {
199 let val = u16::from_be_bytes(<[u8; 2]>::try_from(&self.0[..2]).unwrap());
200 write!(f, "{val:04x}")?;
201 }
202 if self.0.len() >= 5 {
203 write!(f, "…")?;
204 }
205 if self.0.len() >= 4 {
206 let len = self.0.len();
207 let val = u16::from_be_bytes(<[u8; 2]>::try_from(&self.0[len - 2..]).unwrap());
208 write!(f, "{val:04x}")?;
209 }
210 Ok(())
211 }
212}
213
214pub struct BytesDisplay(pub u64);
216
217impl fmt::Display for BytesDisplay {
218 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
219 let mut value = self.0 as f64;
220
221 if value < 1000.0 {
222 return write!(f, "{value} B");
223 }
224 value /= 1024.0;
225
226 if value < 100.0 {
227 return write!(f, "{value:.1} kiB");
228 }
229 if value < 1000.0 {
230 return write!(f, "{value:.0} kiB");
231 }
232 value /= 1024.0;
233
234 if value < 100.0 {
235 return write!(f, "{value:.1} MiB");
236 }
237 if value < 1000.0 {
238 return write!(f, "{value:.0} MiB");
239 }
240 value /= 1024.0;
241
242 if value < 100.0 {
243 return write!(f, "{value:.1} GiB");
244 }
245 if value < 1000.0 {
246 return write!(f, "{value:.0} GiB");
247 }
248 value /= 1024.0;
249
250 if value < 100.0 {
251 return write!(f, "{value:.1} TiB");
252 }
253 if value < 1000.0 {
254 return write!(f, "{value:.0} TiB");
255 }
256 value /= 1024.0;
257
258 write!(f, "{value:.1} PiB")
259
260 }
262}
263
264struct BlockNumberDisplay(u64);
266
267impl fmt::Display for BlockNumberDisplay {
268 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
269 write!(f, "#{}", self.0)?;
270 Ok(())
271 }
272}