1use crate::sys;
2use std::convert::TryInto;
3use std::ffi::{CStr, CString};
4use std::ptr::null_mut;
5
6#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
7pub enum Category {
8 Application,
9 Error,
10 Assert,
11 System,
12 Audio,
13 Video,
14 Render,
15 Input,
16 Test,
17 Custom,
18 Unknown,
19}
20
21impl Category {
22 #[allow(dead_code)]
23 fn from_ll(value: u32) -> Category {
24 if value == sys::SDL_LogCategory::SDL_LOG_CATEGORY_APPLICATION as u32 {
25 Category::Application
26 } else if value == sys::SDL_LogCategory::SDL_LOG_CATEGORY_ERROR as u32 {
27 Category::Error
28 } else if value == sys::SDL_LogCategory::SDL_LOG_CATEGORY_ASSERT as u32 {
29 Category::Assert
30 } else if value == sys::SDL_LogCategory::SDL_LOG_CATEGORY_SYSTEM as u32 {
31 Category::System
32 } else if value == sys::SDL_LogCategory::SDL_LOG_CATEGORY_AUDIO as u32 {
33 Category::Audio
34 } else if value == sys::SDL_LogCategory::SDL_LOG_CATEGORY_VIDEO as u32 {
35 Category::Video
36 } else if value == sys::SDL_LogCategory::SDL_LOG_CATEGORY_RENDER as u32 {
37 Category::Render
38 } else if value == sys::SDL_LogCategory::SDL_LOG_CATEGORY_INPUT as u32 {
39 Category::Input
40 } else if value == sys::SDL_LogCategory::SDL_LOG_CATEGORY_TEST as u32 {
41 Category::Test
42 } else {
43 Category::Custom
44 }
45 }
46
47 fn into_ll(value: Category) -> u32 {
48 return match value {
49 Category::Application => sys::SDL_LogCategory::SDL_LOG_CATEGORY_APPLICATION as u32,
50 Category::Error => sys::SDL_LogCategory::SDL_LOG_CATEGORY_ERROR as u32,
51 Category::Assert => sys::SDL_LogCategory::SDL_LOG_CATEGORY_ASSERT as u32,
52 Category::System => sys::SDL_LogCategory::SDL_LOG_CATEGORY_SYSTEM as u32,
53 Category::Audio => sys::SDL_LogCategory::SDL_LOG_CATEGORY_AUDIO as u32,
54 Category::Video => sys::SDL_LogCategory::SDL_LOG_CATEGORY_VIDEO as u32,
55 Category::Render => sys::SDL_LogCategory::SDL_LOG_CATEGORY_RENDER as u32,
56 Category::Input => sys::SDL_LogCategory::SDL_LOG_CATEGORY_INPUT as u32,
57 Category::Test => sys::SDL_LogCategory::SDL_LOG_CATEGORY_TEST as u32,
58 Category::Custom => sys::SDL_LogCategory::SDL_LOG_CATEGORY_CUSTOM as u32,
59 Category::Unknown => sys::SDL_LogCategory::SDL_LOG_CATEGORY_APPLICATION as u32,
60 };
61 }
62}
63
64#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
65pub enum Priority {
66 Verbose,
67 Debug,
68 Info,
69 Warn,
70 Error,
71 Critical,
72}
73
74impl Priority {
75 fn from_ll(value: sys::SDL_LogPriority) -> Priority {
76 use crate::sys::SDL_LogPriority::*;
77 match value {
78 SDL_LOG_PRIORITY_VERBOSE => Priority::Verbose,
79 SDL_LOG_PRIORITY_DEBUG => Priority::Debug,
80 SDL_LOG_PRIORITY_INFO => Priority::Info,
81 SDL_LOG_PRIORITY_WARN => Priority::Warn,
82 SDL_LOG_PRIORITY_ERROR => Priority::Error,
83 SDL_LOG_PRIORITY_CRITICAL | _ => Priority::Critical,
84 }
85 }
86}
87
88fn dummy(_priority: Priority, _category: Category, _message: &str) {}
89
90#[allow(non_upper_case_globals)]
91static mut custom_log_fn: fn(Priority, Category, &str) = dummy;
93
94unsafe extern "C" fn rust_sdl2_log_fn(
95 _userdata: *mut libc::c_void,
96 category: libc::c_int,
97 priority: sys::SDL_LogPriority,
98 message: *const libc::c_char,
99) {
100 let category = Category::from_ll(category as u32);
101 let priority = Priority::from_ll(priority);
102 let message = CStr::from_ptr(message).to_string_lossy();
103 custom_log_fn(priority, category, &message);
104}
105
106#[doc(alias = "SDL_LogSetOutputFunction")]
107pub fn set_output_function(callback: fn(Priority, Category, &str)) {
108 unsafe {
109 custom_log_fn = callback;
110 sys::SDL_LogSetOutputFunction(Some(rust_sdl2_log_fn), null_mut());
111 };
112}
113
114#[doc(alias = "SDL_Log")]
117pub fn log(message: &str) {
118 let message = message.replace('%', "%%");
119 let message = CString::new(message).unwrap();
120 unsafe {
121 crate::sys::SDL_Log(message.as_ptr());
122 }
123}
124
125#[doc(alias = "SDL_LogCritial")]
127pub fn log_critical(message: &str) {
128 log_with_category(message, Category::Application, Priority::Critical);
129}
130
131#[doc(alias = "SDL_LogDebug")]
133pub fn log_debug(message: &str) {
134 log_with_category(message, Category::Application, Priority::Debug);
135}
136
137#[doc(alias = "SDL_LogError")]
139pub fn log_error(message: &str) {
140 log_with_category(message, Category::Application, Priority::Error);
141}
142
143#[doc(alias = "SDL_LogInfo")]
145pub fn log_info(message: &str) {
146 log_with_category(message, Category::Application, Priority::Info);
147}
148
149#[doc(alias = "SDL_LogVerbose")]
151pub fn log_verbose(message: &str) {
152 log_with_category(message, Category::Application, Priority::Verbose);
153}
154
155#[doc(alias = "SDL_LogWarn")]
157pub fn log_warn(message: &str) {
158 log_with_category(message, Category::Application, Priority::Warn);
159}
160
161pub fn log_with_category(message: &str, category: Category, priority: Priority) {
163 let message = message.replace('%', "%%");
164 let message = CString::new(message).unwrap();
165 let uccategory = Category::into_ll(category).try_into();
166 let ccategory = match uccategory {
167 Err(_) => Category::into_ll(Category::Application).try_into().unwrap(),
168 Ok(success) => success,
169 };
170
171 unsafe {
172 match priority {
173 Priority::Critical => crate::sys::SDL_LogCritical(ccategory, message.as_ptr()),
174 Priority::Debug => crate::sys::SDL_LogDebug(ccategory, message.as_ptr()),
175 Priority::Error => crate::sys::SDL_LogError(ccategory, message.as_ptr()),
176 Priority::Info => crate::sys::SDL_LogInfo(ccategory, message.as_ptr()),
177 Priority::Verbose => crate::sys::SDL_LogVerbose(ccategory, message.as_ptr()),
178 Priority::Warn => crate::sys::SDL_LogWarn(ccategory, message.as_ptr()),
179 }
180 }
181}