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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use jack_sys as j;
use lazy_static::lazy_static;
use std::ffi;
use std::io::{stderr, Write};
use std::sync::{Mutex, Once};
lazy_static! {
static ref INFO_FN: Mutex<Option<fn(&str)>> = Mutex::new(None);
static ref ERROR_FN: Mutex<Option<fn(&str)>> = Mutex::new(None);
}
unsafe extern "C" fn error_wrapper(msg: *const libc::c_char) {
let msg = ffi::CStr::from_ptr(msg)
.to_str()
.unwrap_or("rust failed to interpret error message");
let f = ERROR_FN.lock().unwrap();
match *f {
Some(f) => f(msg),
None => writeln!(&mut stderr(), "{}", msg).unwrap(),
}
}
unsafe extern "C" fn info_wrapper(msg: *const libc::c_char) {
let msg = ffi::CStr::from_ptr(msg)
.to_str()
.unwrap_or("rust failed to interpret info message");
let f = INFO_FN.lock().unwrap();
match *f {
Some(f) => f(msg),
None => println!("{}", msg),
}
}
static IS_INFO_CALLBACK_SET: Once = Once::new();
pub fn set_info_callback(info: fn(&str)) {
*INFO_FN.lock().unwrap() = Some(info);
IS_INFO_CALLBACK_SET.call_once(|| unsafe { j::jack_set_info_function(Some(info_wrapper)) })
}
pub fn info_callback() -> Option<fn(&str)> {
*INFO_FN.lock().unwrap()
}
pub fn reset_info_callback() {
*INFO_FN.lock().unwrap() = None;
}
static IS_ERROR_CALLBACK_SET: Once = Once::new();
pub fn set_error_callback(error: fn(&str)) {
*ERROR_FN.lock().unwrap() = Some(error);
IS_ERROR_CALLBACK_SET.call_once(|| unsafe { j::jack_set_error_function(Some(error_wrapper)) })
}
pub fn error_callback() -> Option<fn(&str)> {
*ERROR_FN.lock().unwrap()
}
pub fn reset_error_callback() {
*ERROR_FN.lock().unwrap() = None;
}
#[cfg(test)]
mod test {
use super::*;
fn null_log_fn(_: &str) {}
#[test]
fn logging_can_set_info() {
reset_info_callback();
assert!(info_callback().is_none());
set_info_callback(null_log_fn);
assert!(info_callback().is_some());
info_callback().unwrap()("Using info callback!.");
reset_info_callback();
assert!(info_callback().is_none());
}
#[test]
fn logging_can_set_error() {
reset_error_callback();
assert!(error_callback().is_none());
set_error_callback(null_log_fn);
assert!(error_callback().is_some());
error_callback().unwrap()("Using error callback!.");
reset_error_callback();
assert!(error_callback().is_none());
}
}