use libc::c_char;
use vsprintf::vsprintf;
use wlroots_sys::{wlr_log_importance, __va_list_tag, wlr_log_init, _wlr_log};
use utils::c_to_rust_string;
use std::ffi::CString;
pub use self::wlr_log_importance::{WLR_SILENT, WLR_ERROR, WLR_INFO,
WLR_DEBUG};
pub type LogVerbosity = wlr_log_importance;
pub type LogCallback = fn(verbosity: LogVerbosity, message: String);
static mut RUST_LOGGING_FN: LogCallback = dummy_callback;
pub fn init_logging<F>(verbosity: LogVerbosity, callback: F)
where F: Into<Option<LogCallback>>
{
unsafe {
match callback.into() {
None => wlr_log_init(verbosity, None),
Some(callback) => {
RUST_LOGGING_FN = callback;
wlr_log_init(verbosity, Some(log_callback));
}
}
}
}
fn dummy_callback(_: LogVerbosity, _: String) {}
unsafe extern "C" fn log_callback(importance: wlr_log_importance,
fmt: *const c_char,
va_list: *mut __va_list_tag) {
let message = vsprintf(fmt, va_list).unwrap_or_else(|_| {
c_to_rust_string(fmt).unwrap_or_else(|| "".into())
});
RUST_LOGGING_FN(importance, message);
}
pub struct Logger;
static LOGGER: Logger = Logger;
impl Logger {
pub fn init<F>(level: log::LevelFilter, callback: F)
where F: Into<Option<LogCallback>>
{
init_logging(
match level {
log::LevelFilter::Off => WLR_SILENT,
log::LevelFilter::Warn | log::LevelFilter::Error => WLR_ERROR,
log::LevelFilter::Info => WLR_INFO,
log::LevelFilter::Debug | log::LevelFilter::Trace => WLR_DEBUG,
},
callback,
);
log::set_logger(&LOGGER).expect(
"Attempted to set a logger after the logging system was already initialized"
);
log::set_max_level(level);
}
}
impl log::Log for Logger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
metadata.level() <= log::max_level()
}
fn log(&self, record: &log::Record) {
if self.enabled(record.metadata()) {
let wlr_level = match record.level() {
log::Level::Warn | log::Level::Error => WLR_ERROR,
log::Level::Info => WLR_INFO,
log::Level::Debug | log::Level::Trace => WLR_DEBUG,
};
let formatted_msg = match (record.file(), record.line()) {
(Some(file), Some(line)) => format!("[{}:{}] {}", file, line, record.args()),
(Some(file), None) => format!("[{}] {}", file, record.args()),
(None, _) => format!("{}", record.args()),
};
let msg = CString::new(formatted_msg)
.expect("Could not convert log message to CString");
unsafe {
_wlr_log(wlr_level, msg.as_ptr());
}
}
}
fn flush(&self) {}
}