1use std::ffi::c_void;
9use std::ptr::NonNull;
10
11use mtl_foundation::{Referencing, UInteger};
12use mtl_sys::{Class, msg_send_0, msg_send_1, sel};
13
14use crate::enums::LogLevel;
15
16#[repr(transparent)]
24pub struct LogStateDescriptor(NonNull<c_void>);
25
26impl LogStateDescriptor {
27 pub fn alloc() -> Option<Self> {
31 unsafe {
32 let cls = Class::get("MTLLogStateDescriptor")?;
33 let ptr: *mut c_void = msg_send_0(cls.as_ptr(), sel!(alloc));
34 Self::from_raw(ptr)
35 }
36 }
37
38 pub fn init(&self) -> Option<Self> {
42 unsafe {
43 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(init));
44 Self::from_raw(ptr)
45 }
46 }
47
48 pub fn new() -> Option<Self> {
50 Self::alloc()?.init()
51 }
52
53 #[inline]
59 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
60 NonNull::new(ptr).map(Self)
61 }
62
63 #[inline]
65 pub fn as_raw(&self) -> *mut c_void {
66 self.0.as_ptr()
67 }
68
69 #[inline]
77 pub fn buffer_size(&self) -> UInteger {
78 unsafe { msg_send_0(self.as_ptr(), sel!(bufferSize)) }
79 }
80
81 #[inline]
85 pub fn set_buffer_size(&self, size: UInteger) {
86 unsafe {
87 msg_send_1::<(), UInteger>(self.as_ptr(), sel!(setBufferSize:), size);
88 }
89 }
90
91 #[inline]
95 pub fn level(&self) -> LogLevel {
96 unsafe { msg_send_0(self.as_ptr(), sel!(level)) }
97 }
98
99 #[inline]
103 pub fn set_level(&self, level: LogLevel) {
104 unsafe {
105 msg_send_1::<(), LogLevel>(self.as_ptr(), sel!(setLevel:), level);
106 }
107 }
108}
109
110impl Default for LogStateDescriptor {
111 fn default() -> Self {
112 Self::new().expect("failed to create LogStateDescriptor")
113 }
114}
115
116impl Clone for LogStateDescriptor {
117 fn clone(&self) -> Self {
118 unsafe {
119 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
120 Self::from_raw(ptr).expect("failed to copy LogStateDescriptor")
121 }
122 }
123}
124
125impl Drop for LogStateDescriptor {
126 fn drop(&mut self) {
127 unsafe {
128 msg_send_0::<()>(self.as_ptr(), sel!(release));
129 }
130 }
131}
132
133impl Referencing for LogStateDescriptor {
134 #[inline]
135 fn as_ptr(&self) -> *const c_void {
136 self.0.as_ptr()
137 }
138}
139
140unsafe impl Send for LogStateDescriptor {}
141unsafe impl Sync for LogStateDescriptor {}
142
143impl std::fmt::Debug for LogStateDescriptor {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 f.debug_struct("LogStateDescriptor")
146 .field("buffer_size", &self.buffer_size())
147 .field("level", &self.level())
148 .finish()
149 }
150}
151
152#[repr(transparent)]
163pub struct LogState(NonNull<c_void>);
164
165impl LogState {
166 #[inline]
172 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
173 NonNull::new(ptr).map(Self)
174 }
175
176 #[inline]
178 pub fn as_raw(&self) -> *mut c_void {
179 self.0.as_ptr()
180 }
181
182 pub unsafe fn add_log_handler_raw(&self, block: *const c_void) {
190 unsafe {
191 msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(addLogHandler:), block);
192 }
193 }
194
195 pub fn add_log_handler<F>(&self, handler: F)
205 where
206 F: Fn(&str, &str, LogLevel, &str) + Send + 'static,
207 {
208 let block = mtl_sys::LogHandlerBlock::from_fn(
209 move |subsystem_ptr: *mut c_void,
210 category_ptr: *mut c_void,
211 level: isize,
212 message_ptr: *mut c_void| {
213 unsafe {
214 let subsystem = nsstring_to_str(subsystem_ptr);
216 let category = nsstring_to_str(category_ptr);
217 let message = nsstring_to_str(message_ptr);
218
219 let log_level = LogLevel(level);
221
222 handler(&subsystem, &category, log_level, &message);
223 }
224 },
225 );
226
227 unsafe {
228 msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(addLogHandler:), block.as_ptr());
229 }
230
231 std::mem::forget(block);
233 }
234}
235
236unsafe fn nsstring_to_str(ns_string: *mut c_void) -> String {
242 if ns_string.is_null() {
243 return String::new();
244 }
245
246 unsafe {
247 let c_str: *const i8 = msg_send_0(ns_string, sel!(UTF8String));
248 if c_str.is_null() {
249 return String::new();
250 }
251
252 std::ffi::CStr::from_ptr(c_str)
253 .to_string_lossy()
254 .into_owned()
255 }
256}
257
258impl Clone for LogState {
259 fn clone(&self) -> Self {
260 unsafe {
261 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
262 }
263 Self(self.0)
264 }
265}
266
267impl Drop for LogState {
268 fn drop(&mut self) {
269 unsafe {
270 msg_send_0::<()>(self.as_ptr(), sel!(release));
271 }
272 }
273}
274
275impl Referencing for LogState {
276 #[inline]
277 fn as_ptr(&self) -> *const c_void {
278 self.0.as_ptr()
279 }
280}
281
282unsafe impl Send for LogState {}
283unsafe impl Sync for LogState {}
284
285impl std::fmt::Debug for LogState {
286 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
287 f.debug_struct("LogState").finish()
288 }
289}
290
291#[cfg(test)]
292mod tests {
293 use super::*;
294
295 #[test]
296 fn test_log_state_descriptor_size() {
297 assert_eq!(
298 std::mem::size_of::<LogStateDescriptor>(),
299 std::mem::size_of::<*mut c_void>()
300 );
301 }
302
303 #[test]
304 fn test_log_state_size() {
305 assert_eq!(
306 std::mem::size_of::<LogState>(),
307 std::mem::size_of::<*mut c_void>()
308 );
309 }
310}