1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//! Integration with [log](https://docs.rs/crate/log)
//!
//! As embedded development implies `#[no_st]` we cannot box
//! our logger so instead simplest approach would be to declare our logger static
//!
//! ```rust
//! use log::info;
//! use cortex_m_log::log::{Logger, init};
//! use cortex_m_log::printer::Dummy;
//!
//! static LOGGER: Logger<Dummy> = Logger {
//!     inner: Dummy,
//!     level: log::LevelFilter::Off
//! };
//!
//! fn main() {
//!     init(&LOGGER).expect("To set logger");
//!
//!     info!("Starting my cute program");
//! }
//! ```
//!
//! Of course since there is no `const-fn` and some printers require
//! Initialization function we need some better way.
//!
//! One way to do it would be to trick compiler by changing lifetime of stack
//! allocated logger to static, obviously unsafe.
//!
//! ```rust,no_run
//! use std::mem;
//!
//! use cortex_m_log::log::{Logger, trick_init};
//! use cortex_m_log::printer::semihosting;
//! use cortex_m_log::modes::InterruptOk;
//!
//! fn main() {
//!     let logger = Logger {
//!         //Uses semihosting as destination with no interrupt control.
//!         inner: semihosting::InterruptOk::<_>::stdout().expect("Get Semihosting stdout"),
//!         level: log::LevelFilter::Info
//!     };
//!     //Haha trust me, it is safe ;)
//!     //As long as logger is not dropped....
//!     unsafe {
//!         let _ = trick_init(&logger);
//!     }
//! }
//! ```
//!
//! Obviously it is UB to drop logger after that and use any of log's macros
use core::mem;
use core::marker;
use crate::printer::Printer;

///Simple Logger implementation
pub struct Logger<P: Printer + marker::Send + marker::Sync> {
    ///Printer implementation
    pub inner: P,
    ///Log level
    pub level: log::LevelFilter,
}

impl<P: Printer + marker::Send + marker::Sync> log::Log for Logger<P> {
    fn enabled(&self, metadata: &log::Metadata) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &log::Record) {
        if self.enabled(record.metadata()) {
            //Pretend we're the Cell
            let inner = &self.inner as *const P as *mut P;
            let inner = unsafe { &mut *inner };

            inner.print(format_args!("{:<5} {}:{} - {}\n", record.level(), record.file().unwrap_or("UNKNOWN"), record.line().unwrap_or(0), record.args()))
        }
    }

    fn flush(&self) {
    }
}

///Initialize logging facilities.
///
///Currently lacks a nice way to set global logger so user
///must himself guarantee static lifetime
pub fn init<P: Printer + marker::Send + marker::Sync>(logger: &'static Logger<P>) -> Result<(), log::SetLoggerError> {
    log::set_max_level(logger.level.clone());
    log::set_logger(logger)
}

#[inline]
///Performs init by tricking compiler into beliving that `&Logger` is static.
///
///This is unsafe and it is up to you to ensure that reference
///will live longer that any attempts to access it
pub unsafe fn trick_init<P: Printer + marker::Send + marker::Sync + 'static>(logger: &Logger<P>) -> Result<(), log::SetLoggerError> {
    let logger: &'static Logger<P> = mem::transmute(logger);
    init(logger)
}