use crate::error::{MdfError, Result};
use mdflib_sys as ffi;
use std::ffi::CStr;
use std::os::raw::c_char;
use std::sync::Mutex;
pub use ffi::MdfLogSeverity;
pub type LogCallback1 = extern "C" fn(severity: MdfLogSeverity, text: *const u8);
pub type LogCallback2 =
extern "C" fn(severity: MdfLogSeverity, function: *const u8, text: *const u8);
static LOG_CALLBACK_1: Mutex<Option<LogCallback1>> = Mutex::new(None);
static LOG_CALLBACK_2: Mutex<Option<LogCallback2>> = Mutex::new(None);
extern "C" fn log_callback_wrapper_1(severity: MdfLogSeverity, text: *const c_char) {
unsafe {
if let Some(callback) = LOG_CALLBACK_1.lock().unwrap().as_ref() {
let rust_text = CStr::from_ptr(text).to_string_lossy();
let bytes = rust_text.as_bytes();
callback(severity, bytes.as_ptr());
}
}
}
extern "C" fn log_callback_wrapper_2(
severity: MdfLogSeverity,
function: *const c_char,
text: *const c_char,
) {
unsafe {
if let Some(callback) = LOG_CALLBACK_2.lock().unwrap().as_ref() {
let rust_function = CStr::from_ptr(function).to_string_lossy();
let rust_text = CStr::from_ptr(text).to_string_lossy();
let function_bytes = rust_function.as_bytes();
let text_bytes = rust_text.as_bytes();
callback(severity, function_bytes.as_ptr(), text_bytes.as_ptr());
}
}
}
pub fn set_log_callback_1(callback: Option<LogCallback1>) -> Result<()> {
unsafe {
if let Some(callback) = callback {
if LOG_CALLBACK_1.lock().unwrap().is_some() {
return Err(MdfError::CallbackError(
"Failed to set log callback, already set".to_string(),
));
}
LOG_CALLBACK_1.lock().unwrap().replace(callback);
ffi::MdfSetLogFunction1(Some(log_callback_wrapper_1));
} else {
LOG_CALLBACK_1.lock().unwrap().take();
ffi::MdfSetLogFunction1(None);
}
}
Ok(())
}
pub fn set_log_callback_2(callback: Option<LogCallback2>) -> Result<()> {
unsafe {
if let Some(callback) = callback {
if LOG_CALLBACK_2.lock().unwrap().is_some() {
return Err(MdfError::CallbackError(
"Failed to set log callback, already set".to_string(),
));
}
LOG_CALLBACK_2.lock().unwrap().replace(callback);
ffi::MdfSetLogFunction2(Some(log_callback_wrapper_2));
} else {
LOG_CALLBACK_2.lock().unwrap().take();
ffi::MdfSetLogFunction2(None);
}
}
Ok(())
}
pub extern "C" fn log_callback(severity: MdfLogSeverity, text: *const u8) {
let text = unsafe { CStr::from_ptr(text as *const c_char).to_string_lossy() };
match severity {
MdfLogSeverity::kTrace => log::trace!("[{severity:?}] {text}"),
MdfLogSeverity::kDebug => log::debug!("[{severity:?}] {text}"),
MdfLogSeverity::kInfo | MdfLogSeverity::kNotice => {
log::info!("[{severity:?}] {text}")
}
_ => log::warn!("[{severity:?}] {text}"),
}
}
pub extern "C" fn log_callback_with_function(
severity: MdfLogSeverity,
function: *const u8,
text: *const u8,
) {
let function = unsafe { CStr::from_ptr(function as *const c_char).to_string_lossy() };
let text = unsafe { CStr::from_ptr(text as *const c_char).to_string_lossy() };
match severity {
MdfLogSeverity::kTrace => log::trace!("[{function}] [{severity:?}]: {text}"),
MdfLogSeverity::kDebug => log::debug!("[{function}] [{severity:?}]: {text}"),
MdfLogSeverity::kInfo | MdfLogSeverity::kNotice => {
log::info!("[{function}] [{severity:?}]: {text}")
}
_ => log::warn!("[{function}] [{severity:?}]: {text}"),
}
}