Krolyxon
Commit feb7482

Branches

Refs →

budctlcratesbudctl-coresrcdebug.rs

70 lines · 1.8 KB · Rust

1//! `--debug` output: a hex dump of every byte sent and received, plus notes on what budctl
2//! decoded and decided. Off by default. It goes to stderr, unless a front end sends it elsewhere
3//! (the Android app, whose stderr goes nowhere).
4
5use std::sync::RwLock;
6use std::sync::atomic::{AtomicBool, Ordering};
7
8static ENABLED: AtomicBool = AtomicBool::new(false);
9
10/// Where debug lines go instead of stderr, once set.
11type Output = Box<dyn Fn(&str) + Send + Sync>;
12static OUTPUT: RwLock<Option<Output>> = RwLock::new(None);
13
14pub fn enable() {
15 ENABLED.store(true, Ordering::Relaxed);
16}
17
18pub fn disable() {
19 ENABLED.store(false, Ordering::Relaxed);
20}
21
22pub fn enabled() -> bool {
23 ENABLED.load(Ordering::Relaxed)
24}
25
26/// Send debug lines to `output` instead of stderr. A later call replaces an earlier one.
27pub fn set_output(output: Output) {
28 if let Ok(mut slot) = OUTPUT.write() {
29 *slot = Some(output);
30 }
31}
32
33/// Print one debug line.
34pub(crate) fn line(text: &str) {
35 if let Ok(slot) = OUTPUT.read()
36 && let Some(output) = slot.as_ref()
37 {
38 output(text);
39 } else {
40 eprintln!("{text}");
41 }
42}
43
44/// Print a note when debugging is on. The message is only built if it will be printed.
45pub(crate) fn note(message: impl FnOnce() -> String) {
46 if enabled() {
47 line(&format!("# {}", message()));
48 }
49}
50
51/// `AA 07 00 …`
52pub fn hex(bytes: &[u8]) -> String {
53 let mut out = String::with_capacity(bytes.len() * 3);
54 for (i, byte) in bytes.iter().enumerate() {
55 if i > 0 {
56 out.push(' ');
57 }
58 out.push_str(&format!("{byte:02X}"));
59 }
60 out
61}
62
63#[cfg(test)]
64mod tests {
65 #[test]
66 fn hex_is_spaced_uppercase() {
67 assert_eq!(super::hex(&[0xAA, 0x07, 0x00]), "AA 07 00");
68 assert_eq!(super::hex(&[]), "");
69 }
70}