use std::ffi::{c_char, c_int, c_void};
const LEVEL_ERROR: c_int = 1;
const LEVEL_INFO: c_int = 2;
const LEVEL_DEBUG: c_int = 3;
const BUFFER: usize = 1024;
unsafe extern "C" {
fn libseat_set_log_handler(handler: Option<Handler>);
fn libseat_set_log_level(level: c_int);
fn vsnprintf(out: *mut c_char, len: usize, format: *const c_char, args: *mut c_void) -> c_int;
}
type Handler = unsafe extern "C" fn(level: c_int, format: *const c_char, args: *mut c_void);
pub(crate) fn install() {
unsafe {
libseat_set_log_handler(Some(trampoline));
libseat_set_log_level(LEVEL_ERROR);
}
}
unsafe extern "C" fn trampoline(level: c_int, format: *const c_char, args: *mut c_void) {
if format.is_null() {
return;
}
let mut buffer = [0_u8; BUFFER];
let written = unsafe {
vsnprintf(
buffer.as_mut_ptr().cast::<c_char>(),
buffer.len(),
format,
args,
)
};
let Ok(written) = usize::try_from(written) else {
return;
};
let written = written.min(buffer.len() - 1);
forward(level, &buffer[..written]);
}
fn forward(level: c_int, message: &[u8]) {
let message = String::from_utf8_lossy(message);
let message = message.trim_end_matches(['\n', '\r']);
if message.is_empty() {
return;
}
match classify(level) {
Level::Error => drmkit_log::log_error!("[libseat] {message}"),
Level::Info => drmkit_log::log_info!("[libseat] {message}"),
Level::Debug => drmkit_log::log_debug!("[libseat] {message}"),
Level::Other => drmkit_log::log_warn!("[libseat] {message}"),
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Level {
Error,
Info,
Debug,
Other,
}
fn classify(level: c_int) -> Level {
match level {
LEVEL_ERROR => Level::Error,
LEVEL_INFO => Level::Info,
LEVEL_DEBUG => Level::Debug,
_ => Level::Other,
}
}
#[cfg(test)]
mod tests {
use super::{Level, classify};
#[test]
fn each_libseat_level_lands_where_the_reference_puts_it() {
assert_eq!(classify(1), Level::Error);
assert_eq!(classify(2), Level::Info);
assert_eq!(classify(3), Level::Debug);
}
#[test]
fn silent_and_unknown_levels_are_warnings() {
assert_eq!(classify(0), Level::Other);
assert_eq!(classify(4), Level::Other);
assert_eq!(classify(-1), Level::Other);
}
}