fontpm_api/
output.rs

1#[cfg(feature = "debug")]
2pub use backtrace;
3use crate::error::Error;
4
5#[derive(PartialEq, Eq)]
6pub enum OutputKind {
7    Ok,
8    Error,
9    Warning,
10    Info,
11    Debug,
12    Trace
13}
14pub struct OutputRecord {
15    pub kind: OutputKind,
16    #[cfg(feature = "debug")]
17    pub module: String,
18    #[cfg(feature = "debug")]
19    pub line: Option<u32>,
20    pub message: String
21}
22
23pub trait CliOutput: Sync {
24    fn is_enabled(&self, kind: OutputKind) -> bool;
25    fn log(&self, record: OutputRecord) -> Result<(), Error>;
26}
27
28static mut IMPL: Option<&dyn CliOutput> = None;
29
30const MISSING_IMPL_MESSAGE: &str = "Log implementation is not set";
31
32pub fn get_impl() -> &'static dyn CliOutput {
33    unsafe {
34        return IMPL.expect(MISSING_IMPL_MESSAGE);
35    }
36}
37
38pub fn set_impl(reference: &'static dyn CliOutput) {
39    unsafe {
40        if let Some(_) = IMPL {
41            panic!("Cannot set log implementation twice"); // Can't be bothered with proper errors
42        }
43        IMPL = Some(reference);
44    }
45}
46
47macro_rules! declare_level_macro {
48    (($d:tt), $name:ident, $level:ident) => {
49        #[macro_export]
50        macro_rules! $name {
51            ($fmt:literal $d(, $fmt_arg: expr)*) => {
52                #[cfg(feature = "debug")]
53                let mut backtrace = $crate::output::backtrace::Backtrace::new();
54                let i = $crate::output::get_impl();
55
56                if i.is_enabled($crate::output::OutputKind::$level) {
57                    let message = format!($fmt $d(, $fmt_arg)*);
58                    #[cfg(feature = "debug")]
59                    let frames = backtrace.frames();
60                    #[cfg(feature = "debug")]
61                    let symbols = frames[0].symbols();
62                    #[cfg(feature = "debug")]
63                    let symbol = &symbols[0];
64                    if let Err(e) = i.log($crate::output::OutputRecord {
65                        kind: $crate::output::OutputKind::$level,
66                        #[cfg(feature = "debug")]
67                        module: String::from(std::module_path!()),
68                        #[cfg(feature = "debug")]
69                        line: symbol.lineno(),
70                        message
71                    }) {
72                        panic!("Could not print: {}", e);
73                    }
74                }
75                ()
76            }
77        }
78    };
79    ($name:ident, $level:ident) => {
80        declare_level_macro!(($), $name, $level);
81    };
82}
83
84declare_level_macro!(error, Error);
85declare_level_macro!(warning, Warning);
86declare_level_macro!(info, Info);
87declare_level_macro!(ok, Ok);
88declare_level_macro!(debug, Debug);
89declare_level_macro!(trace, Trace);