1//! Debugging helpers to handle `WAYLAND_DEBUG` env variable.
2
3use std::{
4 fmt::Display,
5 os::unix::prelude::AsRawFd,
6 time::{SystemTime, UNIX_EPOCH},
7};
8
9use crate::protocol::Argument;
10
11/// The `WAYLAND_DEBUG` env variable is set to debug client.
12pub fn has_debug_client_env() -> bool {
13 matches!(std::env::var_os("WAYLAND_DEBUG"), Some(str) if str == "1" || str == "client")
14}
15
16/// Print the dispatched message to stderr in a following format:
17///
18/// [timestamp] <- interface@id.msg_name(args)
19#[cfg_attr(coverage, coverage(off))]
20pub fn print_dispatched_message<Id: Display, Fd: AsRawFd>(
21 interface: &str,
22 id: u32,
23 msg_name: &str,
24 args: &[Argument<Id, Fd>],
25) {
26 // Add timestamp to output.
27 print_timestamp();
28
29 eprint!(" <- {}@{}.{}, ({})", interface, id, msg_name, DisplaySlice(args));
30
31 // Add a new line.
32 eprintln!();
33}
34
35/// Print the send message to stderr in a following format:
36///
37/// [timestamp] -> interface@id.msg_name(args)
38#[cfg_attr(coverage, coverage(off))]
39pub fn print_send_message<Id: Display, Fd: AsRawFd>(
40 interface: &str,
41 id: u32,
42 msg_name: &str,
43 args: &[Argument<Id, Fd>],
44 discarded: bool,
45) {
46 // Add timestamp to output.
47 print_timestamp();
48
49 if discarded {
50 eprint!("[discarded]");
51 }
52
53 eprint!(" -> {}@{}.{}({})", interface, id, msg_name, DisplaySlice(args));
54
55 // Add a new line.
56 eprintln!();
57}
58
59pub(crate) struct DisplaySlice<'a, D>(pub &'a [D]);
60
61impl<'a, D: Display> Display for DisplaySlice<'a, D> {
62 #[cfg_attr(coverage, coverage(off))]
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 let mut it: Iter<'_, D> = self.0.iter();
65 if let Some(val: &D) = it.next() {
66 write!(f, "{}", val)?;
67 }
68 for val: &D in it {
69 write!(f, ", {}", val)?;
70 }
71 Ok(())
72 }
73}
74
75/// Print timestamp in seconds.microseconds format.
76#[cfg_attr(coverage, coverage(off))]
77fn print_timestamp() {
78 if let Ok(timestamp: Duration) = SystemTime::now().duration_since(UNIX_EPOCH) {
79 // NOTE this is all to make timestamps the same with libwayland, so the log doesn't look
80 // out of place when sys tries to log on their own.
81 let time: u32 = (timestamp.as_secs() * 1000000 + timestamp.subsec_nanos() as u64 / 1000) as u32;
82 // NOTE annotate timestamp so we know which library emmited the log entry.
83 eprint!("[{:7}.{:03}][rs]", time / 1000, time % 1000);
84 }
85}
86