1use log::info;
15
16pub fn emit(line: &str) {
18 info!("{line}");
19}
20
21pub fn header(fields: &[String]) -> String {
24 let mut parts = vec![format!(
25 "{} {}",
26 crate::SCHEDULER_NAME,
27 env!("CARGO_PKG_VERSION")
28 )];
29 parts.extend(fields.iter().cloned());
30 parts.join(" | ")
31}
32
33pub fn kernel_release() -> String {
35 let mut uts: libc::utsname = unsafe { std::mem::zeroed() };
36 if unsafe { libc::uname(&mut uts) } != 0 {
37 return "unknown".to_string();
38 }
39 unsafe { std::ffi::CStr::from_ptr(uts.release.as_ptr()) }
40 .to_string_lossy()
41 .into_owned()
42}
43
44pub fn status(msg: &str) {
47 emit(&format!("{} {}", crate::SCHEDULER_NAME, msg));
48}
49
50pub struct Report {
52 fields: Vec<String>,
53 rows: Vec<(String, String)>,
54}
55
56impl Report {
57 pub fn new() -> Self {
58 Self {
59 fields: Vec::new(),
60 rows: Vec::new(),
61 }
62 }
63
64 pub fn field(&mut self, s: impl Into<String>) {
66 self.fields.push(s.into());
67 }
68
69 pub fn row(&mut self, key: impl Into<String>, value: impl std::fmt::Display) {
70 self.rows.push((key.into(), value.to_string()));
71 }
72
73 pub fn print(&self) {
74 emit(&header(&self.fields));
75 let width = self.rows.iter().map(|(k, _)| k.len()).max().unwrap_or(0);
76 for (key, value) in &self.rows {
77 emit(&format!("{key:<width$} {value}"));
78 }
79 }
80}