1use std::ffi::{c_char, CStr};
7use std::sync::RwLock;
8use {ffi, Error, Result};
9
10#[derive(PartialEq, Eq, Clone, Debug, Copy, PartialOrd, Ord)]
12pub enum LogLevel {
13 Disabled,
15 Normal,
17 Verbose,
19}
20
21impl From<ffi::cubeb_log_level> for LogLevel {
22 fn from(x: ffi::cubeb_log_level) -> Self {
23 use LogLevel::*;
24 match x {
25 ffi::CUBEB_LOG_NORMAL => Normal,
26 ffi::CUBEB_LOG_VERBOSE => Verbose,
27 _ => Disabled,
28 }
29 }
30}
31
32impl From<LogLevel> for ffi::cubeb_log_level {
33 fn from(x: LogLevel) -> Self {
34 use LogLevel::*;
35 match x {
36 Normal => ffi::CUBEB_LOG_NORMAL,
37 Verbose => ffi::CUBEB_LOG_VERBOSE,
38 Disabled => ffi::CUBEB_LOG_DISABLED,
39 }
40 }
41}
42
43pub fn log_enabled() -> bool {
44 unsafe { ffi::cubeb_log_get_level() != LogLevel::Disabled as _ }
45}
46
47static LOG_CALLBACK: RwLock<Option<fn(s: &CStr)>> = RwLock::new(None);
48
49extern "C" {
50 fn cubeb_write_log(fmt: *const c_char, ...);
51}
52
53include!(concat!(env!("OUT_DIR"), "/log_wrap.rs"));
54
55pub unsafe fn rust_write_formatted_msg(s: *const c_char) {
59 if s.is_null() {
60 return;
62 }
63 if let Ok(guard) = LOG_CALLBACK.read() {
64 if let Some(f) = *guard {
65 f(CStr::from_ptr(s));
66 }
67 }
69 }
71
72pub fn set_logging(level: LogLevel, f: Option<fn(s: &CStr)>) -> Result<()> {
73 match LOG_CALLBACK.write() {
74 Ok(mut guard) => {
75 *guard = f;
76 }
77 Err(_) => return Err(Error::Error),
78 }
79 unsafe {
80 call!(ffi::cubeb_set_log_callback(
81 level.into(),
82 if level == LogLevel::Disabled {
83 None
84 } else {
85 Some(cubeb_write_log)
86 }
87 ))
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn test_logging_disabled_by_default() {
97 assert!(!log_enabled());
98 }
99}