1 #![allow(non_camel_case_types)]
2 #![allow(dead_code)]
3 
4 use std::{ffi::c_void, os::raw::c_char};
5 
6 #[repr(C)]
7 #[derive(Debug, Copy, Clone)]
8 pub struct os_log_s {
9     _unused: [u8; 0],
10 }
11 
12 pub type os_log_t = *mut os_log_s;
13 pub type os_log_type_t = u8;
14 
15 pub const OS_LOG_TYPE_DEFAULT: os_log_type_t = 0;
16 pub const OS_LOG_TYPE_INFO: os_log_type_t = 1;
17 pub const OS_LOG_TYPE_DEBUG: os_log_type_t = 2;
18 pub const OS_LOG_TYPE_ERROR: os_log_type_t = 16;
19 pub const OS_LOG_TYPE_FAULT: os_log_type_t = 17;
20 
21 /// Provided by the OS.
22 extern "C" {
os_log_create(subsystem: *const c_char, category: *const c_char) -> os_log_t23     pub fn os_log_create(subsystem: *const c_char, category: *const c_char) -> os_log_t;
os_release(object: *mut c_void)24     pub fn os_release(object: *mut c_void);
os_log_type_enabled(log: os_log_t, level: os_log_type_t) -> bool25     pub fn os_log_type_enabled(log: os_log_t, level: os_log_type_t) -> bool;
26 }
27 
28 /// Wrappers defined in wrapper.c because most of the os_log_* APIs are macros.
29 extern "C" {
wrapped_get_default_log() -> os_log_t30     pub fn wrapped_get_default_log() -> os_log_t;
wrapped_os_log_with_type(log: os_log_t, log_type: os_log_type_t, message: *const c_char)31     pub fn wrapped_os_log_with_type(log: os_log_t, log_type: os_log_type_t, message: *const c_char);
wrapped_os_log_debug(log: os_log_t, message: *const c_char)32     pub fn wrapped_os_log_debug(log: os_log_t, message: *const c_char);
wrapped_os_log_info(log: os_log_t, message: *const c_char)33     pub fn wrapped_os_log_info(log: os_log_t, message: *const c_char);
wrapped_os_log_default(log: os_log_t, message: *const c_char)34     pub fn wrapped_os_log_default(log: os_log_t, message: *const c_char);
wrapped_os_log_error(log: os_log_t, message: *const c_char)35     pub fn wrapped_os_log_error(log: os_log_t, message: *const c_char);
wrapped_os_log_fault(log: os_log_t, message: *const c_char)36     pub fn wrapped_os_log_fault(log: os_log_t, message: *const c_char);
37 }
38 
39 #[cfg(test)]
40 mod tests {
41     use super::*;
42     use std::ffi::CString;
43 
44     #[test]
test_create_and_release()45     fn test_create_and_release() {
46         let subsystem = CString::new("com.example.test").unwrap();
47         let category = CString::new("category").unwrap();
48         let log = unsafe { os_log_create(subsystem.as_ptr(), category.as_ptr()) };
49         assert!(!log.is_null());
50 
51         unsafe {
52             os_release(log as *mut _);
53         }
54     }
55 
56     #[test]
test_output_to_default_log()57     fn test_output_to_default_log() {
58         let message = CString::new("Hello!").unwrap();
59 
60         unsafe {
61             wrapped_os_log_debug(wrapped_get_default_log(), message.as_ptr());
62             wrapped_os_log_info(wrapped_get_default_log(), message.as_ptr());
63             wrapped_os_log_default(wrapped_get_default_log(), message.as_ptr());
64             wrapped_os_log_error(wrapped_get_default_log(), message.as_ptr());
65             wrapped_os_log_fault(wrapped_get_default_log(), message.as_ptr());
66 
67             wrapped_os_log_with_type(
68                 wrapped_get_default_log(),
69                 OS_LOG_TYPE_DEBUG,
70                 message.as_ptr(),
71             );
72             wrapped_os_log_with_type(
73                 wrapped_get_default_log(),
74                 OS_LOG_TYPE_INFO,
75                 message.as_ptr(),
76             );
77             wrapped_os_log_with_type(
78                 wrapped_get_default_log(),
79                 OS_LOG_TYPE_DEFAULT,
80                 message.as_ptr(),
81             );
82             wrapped_os_log_with_type(
83                 wrapped_get_default_log(),
84                 OS_LOG_TYPE_ERROR,
85                 message.as_ptr(),
86             );
87             wrapped_os_log_with_type(
88                 wrapped_get_default_log(),
89                 OS_LOG_TYPE_FAULT,
90                 message.as_ptr(),
91             );
92         }
93     }
94 
95     #[test]
test_output_to_custom_log()96     fn test_output_to_custom_log() {
97         let subsystem = CString::new("com.example.test").unwrap();
98         let category = CString::new("category").unwrap();
99         let log = unsafe { os_log_create(subsystem.as_ptr(), category.as_ptr()) };
100         let message = CString::new("Hello!").unwrap();
101 
102         unsafe {
103             wrapped_os_log_debug(log, message.as_ptr());
104             wrapped_os_log_info(log, message.as_ptr());
105             wrapped_os_log_default(log, message.as_ptr());
106             wrapped_os_log_error(log, message.as_ptr());
107             wrapped_os_log_fault(log, message.as_ptr());
108 
109             wrapped_os_log_with_type(log, OS_LOG_TYPE_DEBUG, message.as_ptr());
110             wrapped_os_log_with_type(log, OS_LOG_TYPE_INFO, message.as_ptr());
111             wrapped_os_log_with_type(log, OS_LOG_TYPE_DEFAULT, message.as_ptr());
112             wrapped_os_log_with_type(log, OS_LOG_TYPE_ERROR, message.as_ptr());
113             wrapped_os_log_with_type(log, OS_LOG_TYPE_FAULT, message.as_ptr());
114 
115             os_release(log as *mut _);
116         }
117     }
118 }
119