1#![deny(unsafe_op_in_unsafe_fn)]
14
15use std::ffi::CStr;
16use std::os::raw::{c_char, c_int};
17
18use log::log_enabled;
19
20#[unsafe(no_mangle)]
22pub extern "C-unwind" fn rustlogger_flush() {
23 log::logger().flush();
24}
25
26unsafe fn optional_str(ptr: *const c_char) -> Option<&'static str> {
33 if ptr.is_null() {
34 None
35 } else {
36 unsafe { std::ffi::CStr::from_ptr(ptr).to_str().ok() }
38 }
39}
40
41pub fn c_to_rust_log_level(level: logger::LogLevel) -> Option<log::Level> {
42 use log::Level::*;
43 match level {
44 logger::_LogLevel_LOGLEVEL_ERROR => Some(Error),
45 logger::_LogLevel_LOGLEVEL_WARNING => Some(Warn),
46 logger::_LogLevel_LOGLEVEL_INFO => Some(Info),
47 logger::_LogLevel_LOGLEVEL_DEBUG => Some(Debug),
48 logger::_LogLevel_LOGLEVEL_TRACE => Some(Trace),
49 logger::_LogLevel_LOGLEVEL_UNSET => None,
50 _ => panic!("Unexpected log level {level}"),
51 }
52}
53
54#[unsafe(no_mangle)]
56pub extern "C-unwind" fn rustlogger_isEnabled(level: logger::LogLevel) -> c_int {
57 let level = c_to_rust_log_level(level).unwrap();
58 log_enabled!(level).into()
59}
60
61#[unsafe(no_mangle)]
68pub unsafe extern "C-unwind" fn rustlogger_log(
69 level: logger::LogLevel,
70 file_name: *const c_char,
71 fn_name: *const c_char,
72 line: i32,
73 format: *const c_char,
74 args: va_list::VaList,
75) {
76 let log_level = c_to_rust_log_level(level).unwrap();
77
78 if !log_enabled!(log_level) {
79 return;
80 }
81
82 assert!(!format.is_null());
83 let format = unsafe { CStr::from_ptr(format) };
84 let mut msgbuf = formatting_nostd::FormatBuffer::<500>::new();
85 unsafe { msgbuf.sprintf(format, args) };
87
88 log::logger().log(
89 &log::Record::builder()
90 .level(log_level)
91 .file_static(unsafe { optional_str(file_name) })
93 .line(Some(u32::try_from(line).unwrap()))
94 .module_path_static(unsafe { optional_str(fn_name) })
96 .args(format_args!("{msgbuf}"))
97 .build(),
98 );
99}