use cyclonedds_rust_sys::*;
use std::ffi::CStr;
use std::sync::Mutex;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LogCategory(pub u32);
impl LogCategory {
pub const NONE: LogCategory = LogCategory(0);
pub const FATAL: LogCategory = LogCategory(1);
pub const ERROR: LogCategory = LogCategory(2);
pub const WARNING: LogCategory = LogCategory(4);
pub const INFO: LogCategory = LogCategory(8);
pub const DEBUG: LogCategory = LogCategory(16);
pub const TRACE: LogCategory = LogCategory(32);
pub const ALL: LogCategory = LogCategory(0x3F);
}
impl std::ops::BitOr for LogCategory {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
LogCategory(self.0 | rhs.0)
}
}
impl std::ops::BitOrAssign for LogCategory {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
#[derive(Debug, Clone)]
pub struct LogEntry {
pub message: String,
pub category: LogCategory,
pub file: Option<String>,
pub line: Option<u32>,
pub function: Option<String>,
pub domain_id: Option<u32>,
}
type LogCallback = Box<dyn Fn(LogEntry) + Send + Sync>;
static LOG_SINK: Mutex<Option<LogCallback>> = Mutex::new(None);
static TRACE_SINK: Mutex<Option<LogCallback>> = Mutex::new(None);
unsafe extern "C" fn log_trampoline(_logdatum: *mut std::ffi::c_void, data: *const dds_log_data_t) {
if data.is_null() {
return;
}
let d = &*data;
let message = if d.message.is_null() || d.size == 0 {
String::new()
} else {
let bytes = std::slice::from_raw_parts(d.message as *const u8, d.size);
let s = bytes.split(|&b| b == 0).next().unwrap_or(&[]);
String::from_utf8_lossy(s).into_owned()
};
let file = if d.file.is_null() {
None
} else {
Some(CStr::from_ptr(d.file).to_string_lossy().into_owned())
};
let function = if d.function.is_null() {
None
} else {
Some(CStr::from_ptr(d.function).to_string_lossy().into_owned())
};
let domain_id = if d.domid == u32::MAX {
None
} else {
Some(d.domid)
};
let entry = LogEntry {
message,
category: LogCategory(d.priority),
file,
line: if d.line == 0 { None } else { Some(d.line) },
function,
domain_id,
};
if let Ok(guard) = LOG_SINK.lock() {
if let Some(ref cb) = *guard {
cb(entry.clone());
}
}
if let Ok(guard) = TRACE_SINK.lock() {
if let Some(ref cb) = *guard {
cb(entry);
}
}
}
pub fn set_log_sink(callback: Option<Box<dyn Fn(LogEntry) + Send + Sync>>) {
let mut slot = LOG_SINK.lock().unwrap();
*slot = callback;
let (cb, arg) = if slot.is_some() {
(
Some(
log_trampoline
as unsafe extern "C" fn(
*mut std::ffi::c_void,
*const cyclonedds_rust_sys::dds_log_data_t,
),
),
std::ptr::null_mut::<std::ffi::c_void>(),
)
} else {
(None, std::ptr::null_mut::<std::ffi::c_void>())
};
unsafe {
dds_set_log_sink(cb, arg);
}
}
pub fn set_trace_sink(callback: Option<Box<dyn Fn(LogEntry) + Send + Sync>>) {
let mut slot = TRACE_SINK.lock().unwrap();
*slot = callback;
let (cb, arg) = if slot.is_some() {
(
Some(
log_trampoline
as unsafe extern "C" fn(
*mut std::ffi::c_void,
*const cyclonedds_rust_sys::dds_log_data_t,
),
),
std::ptr::null_mut::<std::ffi::c_void>(),
)
} else {
(None, std::ptr::null_mut::<std::ffi::c_void>())
};
unsafe {
dds_set_trace_sink(cb, arg);
}
}