1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
pub fn cubeb_log_internal_buf_fmt<'a>(
buf: &'a mut [u8; 1024],
file: &str,
line: u32,
msg: &str,
) -> &'a std::ffi::CStr {
use std::io::Write;
let filename = std::path::Path::new(file)
.file_name()
.unwrap()
.to_str()
.unwrap();
let len = filename.len() + ((line as f32).log10().trunc() as usize) + msg.len() + 5;
debug_assert!(len < buf.len(), "log will be truncated");
let _ = writeln!(&mut buf[..], "{}:{}: {}", filename, line, msg);
let last = std::cmp::min(len, buf.len() - 1);
buf[last] = 0;
let cstr = unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(&buf[..=last]) };
cstr
}
#[macro_export]
macro_rules! cubeb_log_internal {
($log_callback: expr, $level: expr, $fmt: expr, $($arg: expr),+) => {
cubeb_log_internal!($log_callback, $level, format!($fmt, $($arg),*));
};
($log_callback: expr, $level: expr, $msg: expr) => {
#[allow(unused_unsafe)]
unsafe {
if $level <= $crate::ffi::g_cubeb_log_level.into() {
if let Some(log_callback) = $log_callback {
let mut buf = [0u8; 1024];
log_callback(
$crate::log::cubeb_log_internal_buf_fmt(&mut buf, file!(), line!(), &$msg)
.as_ptr(),
);
}
}
}
};
}
#[macro_export]
macro_rules! cubeb_log {
($($arg: expr),+) => (cubeb_log_internal!($crate::ffi::g_cubeb_log_callback, $crate::LogLevel::Normal, $($arg),+));
}
#[macro_export]
macro_rules! cubeb_logv {
($($arg: expr),+) => (cubeb_log_internal!($crate::ffi::g_cubeb_log_callback, $crate::LogLevel::Verbose, $($arg),+));
}
#[macro_export]
macro_rules! cubeb_alog {
($($arg: expr),+) => (cubeb_log_internal!($crate::ffi::cubeb_async_log.into(), $crate::LogLevel::Normal, $($arg),+));
}
#[macro_export]
macro_rules! cubeb_alogv {
($($arg: expr),+) => (cubeb_log_internal!($crate::ffi::cubeb_async_log.into(), $crate::LogLevel::Verbose, $($arg),+));
}
#[cfg(test)]
mod tests {
#[test]
fn test_normal_logging_sync() {
cubeb_log!("This is synchronous log output at normal level");
cubeb_log!("{} Formatted log", 1);
cubeb_log!("{} Formatted {} log {}", 1, 2, 3);
}
#[test]
fn test_verbose_logging_sync() {
cubeb_logv!("This is synchronous log output at verbose level");
cubeb_logv!("{} Formatted log", 1);
cubeb_logv!("{} Formatted {} log {}", 1, 2, 3);
}
#[test]
fn test_normal_logging_async() {
cubeb_alog!("This is asynchronous log output at normal level");
cubeb_alog!("{} Formatted log", 1);
cubeb_alog!("{} Formatted {} log {}", 1, 2, 3);
}
#[test]
fn test_verbose_logging_async() {
cubeb_alogv!("This is asynchronous log output at verbose level");
cubeb_alogv!("{} Formatted log", 1);
cubeb_alogv!("{} Formatted {} log {}", 1, 2, 3);
}
}