1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::{borrow::Cow, ffi::CStr, fmt, ptr}; |
4 | |
5 | use glib::once_cell::sync::Lazy; |
6 | use glib::{ffi::gpointer, prelude::*, translate::*, IntoGStr, IntoOptionalGStr}; |
7 | use libc::c_char; |
8 | |
9 | use crate::DebugLevel; |
10 | |
11 | #[derive (PartialEq, Eq)] |
12 | #[doc (alias = "GstDebugMessage" )] |
13 | pub struct DebugMessage(ptr::NonNull<ffi::GstDebugMessage>); |
14 | |
15 | impl fmt::Debug for DebugMessage { |
16 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
17 | f.debug_tuple(name:"DebugMessage" ).field(&self.get()).finish() |
18 | } |
19 | } |
20 | |
21 | impl DebugMessage { |
22 | #[doc (alias = "gst_debug_message_get" )] |
23 | #[inline ] |
24 | pub fn get(&self) -> Option<Cow<glib::GStr>> { |
25 | unsafe { |
26 | let message = ffi::gst_debug_message_get(self.0.as_ptr()); |
27 | |
28 | if message.is_null() { |
29 | None |
30 | } else { |
31 | Some(glib::GStr::from_ptr_lossy(message)) |
32 | } |
33 | } |
34 | } |
35 | |
36 | #[cfg (feature = "v1_22" )] |
37 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
38 | #[doc (alias = "gst_debug_message_get_id" )] |
39 | #[inline ] |
40 | pub fn id(&self) -> Option<&glib::GStr> { |
41 | unsafe { |
42 | let id = ffi::gst_debug_message_get_id(self.0.as_ptr()); |
43 | |
44 | if id.is_null() { |
45 | None |
46 | } else { |
47 | Some(glib::GStr::from_ptr(id)) |
48 | } |
49 | } |
50 | } |
51 | } |
52 | |
53 | #[derive (PartialEq, Eq, Clone, Copy)] |
54 | #[doc (alias = "GstDebugCategory" )] |
55 | #[repr (transparent)] |
56 | pub struct DebugCategory(Option<ptr::NonNull<ffi::GstDebugCategory>>); |
57 | |
58 | impl DebugCategory { |
59 | #[doc (alias = "gst_debug_category_new" )] |
60 | #[doc (alias = "GST_DEBUG_CATEGORY" )] |
61 | #[doc (alias = "GST_DEBUG_CATEGORY_INIT" )] |
62 | pub fn new( |
63 | name: &str, |
64 | color: crate::DebugColorFlags, |
65 | description: Option<&str>, |
66 | ) -> DebugCategory { |
67 | skip_assert_initialized!(); |
68 | extern "C" { |
69 | fn _gst_debug_category_new( |
70 | name: *const c_char, |
71 | color: ffi::GstDebugColorFlags, |
72 | description: *const c_char, |
73 | ) -> *mut ffi::GstDebugCategory; |
74 | } |
75 | |
76 | // Gets the category if it exists already |
77 | unsafe { |
78 | let ptr = name.run_with_gstr(|name| { |
79 | description.run_with_gstr(|description| { |
80 | _gst_debug_category_new( |
81 | name.to_glib_none().0, |
82 | color.into_glib(), |
83 | description.to_glib_none().0, |
84 | ) |
85 | }) |
86 | }); |
87 | |
88 | // Can be NULL if the debug system is compiled out |
89 | DebugCategory(ptr::NonNull::new(ptr)) |
90 | } |
91 | } |
92 | |
93 | #[doc (alias = "gst_debug_get_category" )] |
94 | #[inline ] |
95 | pub fn get(name: &str) -> Option<DebugCategory> { |
96 | skip_assert_initialized!(); |
97 | unsafe { |
98 | extern "C" { |
99 | fn _gst_debug_get_category(name: *const c_char) -> *mut ffi::GstDebugCategory; |
100 | } |
101 | |
102 | let cat = name.run_with_gstr(|name| _gst_debug_get_category(name.to_glib_none().0)); |
103 | |
104 | if cat.is_null() { |
105 | None |
106 | } else { |
107 | Some(DebugCategory(Some(ptr::NonNull::new_unchecked(cat)))) |
108 | } |
109 | } |
110 | } |
111 | |
112 | #[doc (alias = "get_threshold" )] |
113 | #[doc (alias = "gst_debug_category_get_threshold" )] |
114 | #[inline ] |
115 | pub fn threshold(self) -> crate::DebugLevel { |
116 | match self.0 { |
117 | Some(cat) => unsafe { from_glib(cat.as_ref().threshold) }, |
118 | None => crate::DebugLevel::None, |
119 | } |
120 | } |
121 | |
122 | #[doc (alias = "gst_debug_category_set_threshold" )] |
123 | #[inline ] |
124 | pub fn set_threshold(self, threshold: crate::DebugLevel) { |
125 | if let Some(cat) = self.0 { |
126 | unsafe { ffi::gst_debug_category_set_threshold(cat.as_ptr(), threshold.into_glib()) } |
127 | } |
128 | } |
129 | |
130 | #[doc (alias = "gst_debug_category_reset_threshold" )] |
131 | #[inline ] |
132 | pub fn reset_threshold(self) { |
133 | if let Some(cat) = self.0 { |
134 | unsafe { ffi::gst_debug_category_reset_threshold(cat.as_ptr()) } |
135 | } |
136 | } |
137 | |
138 | #[inline ] |
139 | pub fn above_threshold(self, level: crate::DebugLevel) -> bool { |
140 | match self.0 { |
141 | Some(cat) => unsafe { cat.as_ref().threshold >= level.into_glib() }, |
142 | None => false, |
143 | } |
144 | } |
145 | |
146 | #[doc (alias = "get_color" )] |
147 | #[doc (alias = "gst_debug_category_get_color" )] |
148 | #[inline ] |
149 | pub fn color(self) -> crate::DebugColorFlags { |
150 | match self.0 { |
151 | Some(cat) => unsafe { from_glib(cat.as_ref().color) }, |
152 | None => crate::DebugColorFlags::empty(), |
153 | } |
154 | } |
155 | |
156 | #[doc (alias = "get_name" )] |
157 | #[doc (alias = "gst_debug_category_get_name" )] |
158 | #[inline ] |
159 | pub fn name<'a>(self) -> &'a str { |
160 | match self.0 { |
161 | Some(cat) => unsafe { CStr::from_ptr(cat.as_ref().name).to_str().unwrap() }, |
162 | None => "" , |
163 | } |
164 | } |
165 | |
166 | #[doc (alias = "get_description" )] |
167 | #[doc (alias = "gst_debug_category_get_description" )] |
168 | #[inline ] |
169 | pub fn description<'a>(self) -> Option<&'a str> { |
170 | let cat = self.0?; |
171 | |
172 | unsafe { |
173 | let ptr = cat.as_ref().description; |
174 | |
175 | if ptr.is_null() { |
176 | None |
177 | } else { |
178 | Some(CStr::from_ptr(ptr).to_str().unwrap()) |
179 | } |
180 | } |
181 | } |
182 | |
183 | #[inline ] |
184 | #[doc (alias = "gst_debug_log" )] |
185 | #[doc (alias = "gst_debug_log_literal" )] |
186 | pub fn log( |
187 | self, |
188 | obj: Option<&impl IsA<glib::Object>>, |
189 | level: crate::DebugLevel, |
190 | file: &glib::GStr, |
191 | function: &str, |
192 | line: u32, |
193 | args: fmt::Arguments, |
194 | ) { |
195 | if !self.above_threshold(level) { |
196 | return; |
197 | } |
198 | |
199 | self.log_unfiltered_internal( |
200 | obj.map(|obj| obj.as_ref()), |
201 | level, |
202 | file, |
203 | function, |
204 | line, |
205 | args, |
206 | ) |
207 | } |
208 | |
209 | #[inline ] |
210 | #[doc (alias = "gst_debug_log_literal" )] |
211 | pub fn log_literal( |
212 | self, |
213 | obj: Option<&impl IsA<glib::Object>>, |
214 | level: crate::DebugLevel, |
215 | file: &glib::GStr, |
216 | function: &str, |
217 | line: u32, |
218 | msg: &glib::GStr, |
219 | ) { |
220 | if !self.above_threshold(level) { |
221 | return; |
222 | } |
223 | |
224 | self.log_literal_unfiltered_internal( |
225 | obj.map(|obj| obj.as_ref()), |
226 | level, |
227 | file, |
228 | function, |
229 | line, |
230 | msg, |
231 | ) |
232 | } |
233 | |
234 | // rustdoc-stripper-ignore-next |
235 | /// Logs without checking the log level. |
236 | #[inline ] |
237 | #[doc (alias = "gst_debug_log" )] |
238 | pub fn log_unfiltered( |
239 | self, |
240 | obj: Option<&impl IsA<glib::Object>>, |
241 | level: crate::DebugLevel, |
242 | file: &glib::GStr, |
243 | function: &str, |
244 | line: u32, |
245 | args: fmt::Arguments, |
246 | ) { |
247 | self.log_unfiltered_internal( |
248 | obj.map(|obj| obj.as_ref()), |
249 | level, |
250 | file, |
251 | function, |
252 | line, |
253 | args, |
254 | ) |
255 | } |
256 | |
257 | // rustdoc-stripper-ignore-next |
258 | /// Logs without checking the log level. |
259 | #[inline ] |
260 | #[doc (alias = "gst_debug_log_literal" )] |
261 | pub fn log_literal_unfiltered( |
262 | self, |
263 | obj: Option<&impl IsA<glib::Object>>, |
264 | level: crate::DebugLevel, |
265 | file: &glib::GStr, |
266 | function: &str, |
267 | line: u32, |
268 | msg: &glib::GStr, |
269 | ) { |
270 | self.log_literal_unfiltered_internal( |
271 | obj.map(|obj| obj.as_ref()), |
272 | level, |
273 | file, |
274 | function, |
275 | line, |
276 | msg, |
277 | ) |
278 | } |
279 | |
280 | #[inline (never)] |
281 | fn log_unfiltered_internal( |
282 | self, |
283 | obj: Option<&glib::Object>, |
284 | level: crate::DebugLevel, |
285 | file: &glib::GStr, |
286 | function: &str, |
287 | line: u32, |
288 | args: fmt::Arguments, |
289 | ) { |
290 | let mut w = smallvec::SmallVec::<[u8; 256]>::new(); |
291 | |
292 | // Can't really happen but better safe than sorry |
293 | if std::io::Write::write_fmt(&mut w, args).is_err() { |
294 | return; |
295 | } |
296 | w.push(0); |
297 | |
298 | self.log_literal_unfiltered_internal(obj, level, file, function, line, unsafe { |
299 | glib::GStr::from_utf8_with_nul_unchecked(&w) |
300 | }); |
301 | } |
302 | |
303 | #[inline (never)] |
304 | fn log_literal_unfiltered_internal( |
305 | self, |
306 | obj: Option<&glib::Object>, |
307 | level: crate::DebugLevel, |
308 | file: &glib::GStr, |
309 | function: &str, |
310 | line: u32, |
311 | msg: &glib::GStr, |
312 | ) { |
313 | let cat = match self.0 { |
314 | Some(cat) => cat, |
315 | None => return, |
316 | }; |
317 | |
318 | let obj_ptr = match obj { |
319 | Some(obj) => obj.as_ptr(), |
320 | None => ptr::null_mut(), |
321 | }; |
322 | |
323 | function.run_with_gstr(|function| { |
324 | #[cfg (feature = "v1_20" )] |
325 | unsafe { |
326 | ffi::gst_debug_log_literal( |
327 | cat.as_ptr(), |
328 | level.into_glib(), |
329 | file.as_ptr(), |
330 | function.as_ptr(), |
331 | line as i32, |
332 | obj_ptr, |
333 | msg.as_ptr(), |
334 | ); |
335 | } |
336 | #[cfg (not(feature = "v1_20" ))] |
337 | unsafe { |
338 | ffi::gst_debug_log( |
339 | cat.as_ptr(), |
340 | level.into_glib(), |
341 | file.as_ptr(), |
342 | function.as_ptr(), |
343 | line as i32, |
344 | obj_ptr, |
345 | b"%s \0" .as_ptr() as *const _, |
346 | msg.as_ptr(), |
347 | ); |
348 | } |
349 | }); |
350 | } |
351 | |
352 | #[cfg (feature = "v1_22" )] |
353 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
354 | #[inline ] |
355 | #[doc (alias = "gst_debug_log_id" )] |
356 | pub fn log_id( |
357 | self, |
358 | id: impl AsRef<glib::GStr>, |
359 | level: crate::DebugLevel, |
360 | file: &glib::GStr, |
361 | function: &str, |
362 | line: u32, |
363 | args: fmt::Arguments, |
364 | ) { |
365 | if !self.above_threshold(level) { |
366 | return; |
367 | } |
368 | |
369 | self.log_id_unfiltered_internal(id.as_ref(), level, file, function, line, args); |
370 | } |
371 | |
372 | #[cfg (feature = "v1_22" )] |
373 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
374 | #[inline ] |
375 | #[doc (alias = "gst_debug_log_id_literal" )] |
376 | pub fn log_id_literal( |
377 | self, |
378 | id: impl AsRef<glib::GStr>, |
379 | level: crate::DebugLevel, |
380 | file: &glib::GStr, |
381 | function: &str, |
382 | line: u32, |
383 | msg: &glib::GStr, |
384 | ) { |
385 | if !self.above_threshold(level) { |
386 | return; |
387 | } |
388 | |
389 | self.log_id_literal_unfiltered_internal(id.as_ref(), level, file, function, line, msg); |
390 | } |
391 | |
392 | #[cfg (feature = "v1_22" )] |
393 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
394 | // rustdoc-stripper-ignore-next |
395 | /// Logs without checking the log level. |
396 | #[inline ] |
397 | #[doc (alias = "gst_debug_log_id" )] |
398 | pub fn log_id_unfiltered( |
399 | self, |
400 | id: impl AsRef<glib::GStr>, |
401 | level: crate::DebugLevel, |
402 | file: &glib::GStr, |
403 | function: &str, |
404 | line: u32, |
405 | args: fmt::Arguments, |
406 | ) { |
407 | self.log_id_unfiltered_internal(id.as_ref(), level, file, function, line, args) |
408 | } |
409 | |
410 | #[cfg (feature = "v1_22" )] |
411 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_22" )))] |
412 | // rustdoc-stripper-ignore-next |
413 | /// Logs without checking the log level. |
414 | #[inline ] |
415 | #[doc (alias = "gst_debug_log_id_literal" )] |
416 | pub fn log_id_literal_unfiltered( |
417 | self, |
418 | id: impl AsRef<glib::GStr>, |
419 | level: crate::DebugLevel, |
420 | file: &glib::GStr, |
421 | function: &str, |
422 | line: u32, |
423 | msg: &glib::GStr, |
424 | ) { |
425 | self.log_id_literal_unfiltered_internal(id.as_ref(), level, file, function, line, msg) |
426 | } |
427 | |
428 | #[cfg (feature = "v1_22" )] |
429 | #[inline (never)] |
430 | fn log_id_unfiltered_internal( |
431 | self, |
432 | id: &glib::GStr, |
433 | level: crate::DebugLevel, |
434 | file: &glib::GStr, |
435 | function: &str, |
436 | line: u32, |
437 | args: fmt::Arguments, |
438 | ) { |
439 | let mut w = smallvec::SmallVec::<[u8; 256]>::new(); |
440 | |
441 | // Can't really happen but better safe than sorry |
442 | if std::io::Write::write_fmt(&mut w, args).is_err() { |
443 | return; |
444 | } |
445 | |
446 | self.log_id_literal_unfiltered_internal(id, level, file, function, line, unsafe { |
447 | glib::GStr::from_utf8_with_nul_unchecked(&w) |
448 | }); |
449 | } |
450 | |
451 | #[cfg (feature = "v1_22" )] |
452 | #[inline (never)] |
453 | fn log_id_literal_unfiltered_internal( |
454 | self, |
455 | id: &glib::GStr, |
456 | level: crate::DebugLevel, |
457 | file: &glib::GStr, |
458 | function: &str, |
459 | line: u32, |
460 | msg: &glib::GStr, |
461 | ) { |
462 | let cat = match self.0 { |
463 | Some(cat) => cat, |
464 | None => return, |
465 | }; |
466 | |
467 | function.run_with_gstr(|function| unsafe { |
468 | ffi::gst_debug_log_id_literal( |
469 | cat.as_ptr(), |
470 | level.into_glib(), |
471 | file.as_ptr(), |
472 | function.as_ptr(), |
473 | line as i32, |
474 | id.as_ptr(), |
475 | msg.as_ptr(), |
476 | ); |
477 | }); |
478 | } |
479 | |
480 | #[doc (alias = "get_all_categories" )] |
481 | #[doc (alias = "gst_debug_get_all_categories" )] |
482 | #[inline ] |
483 | pub fn all_categories() -> glib::SList<DebugCategory> { |
484 | unsafe { glib::SList::from_glib_container(ffi::gst_debug_get_all_categories()) } |
485 | } |
486 | |
487 | #[cfg (feature = "v1_18" )] |
488 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_18" )))] |
489 | #[doc (alias = "gst_debug_log_get_line" )] |
490 | #[inline ] |
491 | pub fn get_line( |
492 | &self, |
493 | level: crate::DebugLevel, |
494 | file: &glib::GStr, |
495 | function: &glib::GStr, |
496 | line: u32, |
497 | object: Option<&LoggedObject>, |
498 | message: &DebugMessage, |
499 | ) -> Option<glib::GString> { |
500 | let cat = self.0?; |
501 | |
502 | unsafe { |
503 | from_glib_full(ffi::gst_debug_log_get_line( |
504 | cat.as_ptr(), |
505 | level.into_glib(), |
506 | file.as_ptr(), |
507 | function.as_ptr(), |
508 | line as i32, |
509 | object.map(|o| o.as_ptr()).unwrap_or(ptr::null_mut()), |
510 | message.0.as_ptr(), |
511 | )) |
512 | } |
513 | } |
514 | } |
515 | |
516 | unsafe impl Sync for DebugCategory {} |
517 | unsafe impl Send for DebugCategory {} |
518 | |
519 | impl fmt::Debug for DebugCategory { |
520 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
521 | f.debug_tuple(name:"DebugCategory" ).field(&self.name()).finish() |
522 | } |
523 | } |
524 | |
525 | impl GlibPtrDefault for DebugCategory { |
526 | type GlibType = *mut ffi::GstDebugCategory; |
527 | } |
528 | |
529 | unsafe impl TransparentPtrType for DebugCategory {} |
530 | |
531 | impl FromGlibPtrNone<*mut ffi::GstDebugCategory> for DebugCategory { |
532 | #[inline ] |
533 | unsafe fn from_glib_none(ptr: *mut ffi::GstDebugCategory) -> Self { |
534 | debug_assert!(!ptr.is_null()); |
535 | DebugCategory(Some(ptr::NonNull::new_unchecked(ptr))) |
536 | } |
537 | } |
538 | |
539 | impl FromGlibPtrFull<*mut ffi::GstDebugCategory> for DebugCategory { |
540 | #[inline ] |
541 | unsafe fn from_glib_full(ptr: *mut ffi::GstDebugCategory) -> Self { |
542 | debug_assert!(!ptr.is_null()); |
543 | DebugCategory(Some(ptr::NonNull::new_unchecked(ptr))) |
544 | } |
545 | } |
546 | |
547 | pub static CAT_RUST: Lazy<DebugCategory> = Lazy::new(|| { |
548 | DebugCategory::new( |
549 | name:"GST_RUST" , |
550 | color:crate::DebugColorFlags::UNDERLINE, |
551 | description:Some("GStreamer's Rust binding core" ), |
552 | ) |
553 | }); |
554 | |
555 | macro_rules! declare_debug_category_from_name( |
556 | ($cat:ident, $cat_name:expr) => ( |
557 | pub static $cat: Lazy<DebugCategory> = Lazy::new(|| DebugCategory::get($cat_name) |
558 | .expect(&format!("Unable to find `DebugCategory` with name {}" , $cat_name))); |
559 | ); |
560 | ); |
561 | |
562 | declare_debug_category_from_name!(CAT_DEFAULT, "default" ); |
563 | declare_debug_category_from_name!(CAT_GST_INIT, "GST_INIT" ); |
564 | declare_debug_category_from_name!(CAT_MEMORY, "GST_MEMORY" ); |
565 | declare_debug_category_from_name!(CAT_PARENTAGE, "GST_PARENTAGE" ); |
566 | declare_debug_category_from_name!(CAT_STATES, "GST_STATES" ); |
567 | declare_debug_category_from_name!(CAT_SCHEDULING, "GST_SCHEDULING" ); |
568 | declare_debug_category_from_name!(CAT_BUFFER, "GST_BUFFER" ); |
569 | declare_debug_category_from_name!(CAT_BUFFER_LIST, "GST_BUFFER_LIST" ); |
570 | declare_debug_category_from_name!(CAT_BUS, "GST_BUS" ); |
571 | declare_debug_category_from_name!(CAT_CAPS, "GST_CAPS" ); |
572 | declare_debug_category_from_name!(CAT_CLOCK, "GST_CLOCK" ); |
573 | declare_debug_category_from_name!(CAT_ELEMENT_PADS, "GST_ELEMENT_PADS" ); |
574 | declare_debug_category_from_name!(CAT_PADS, "GST_PADS" ); |
575 | declare_debug_category_from_name!(CAT_PERFORMANCE, "GST_PERFORMANCE" ); |
576 | declare_debug_category_from_name!(CAT_PIPELINE, "GST_PIPELINE" ); |
577 | declare_debug_category_from_name!(CAT_PLUGIN_LOADING, "GST_PLUGIN_LOADING" ); |
578 | declare_debug_category_from_name!(CAT_PLUGIN_INFO, "GST_PLUGIN_INFO" ); |
579 | declare_debug_category_from_name!(CAT_PROPERTIES, "GST_PROPERTIES" ); |
580 | declare_debug_category_from_name!(CAT_NEGOTIATION, "GST_NEGOTIATION" ); |
581 | declare_debug_category_from_name!(CAT_REFCOUNTING, "GST_REFCOUNTING" ); |
582 | declare_debug_category_from_name!(CAT_ERROR_SYSTEM, "GST_ERROR_SYSTEM" ); |
583 | declare_debug_category_from_name!(CAT_EVENT, "GST_EVENT" ); |
584 | declare_debug_category_from_name!(CAT_MESSAGE, "GST_MESSAGE" ); |
585 | declare_debug_category_from_name!(CAT_PARAMS, "GST_PARAMS" ); |
586 | declare_debug_category_from_name!(CAT_CALL_TRACE, "GST_CALL_TRACE" ); |
587 | declare_debug_category_from_name!(CAT_SIGNAL, "GST_SIGNAL" ); |
588 | declare_debug_category_from_name!(CAT_PROBE, "GST_PROBE" ); |
589 | declare_debug_category_from_name!(CAT_REGISTRY, "GST_REGISTRY" ); |
590 | declare_debug_category_from_name!(CAT_QOS, "GST_QOS" ); |
591 | declare_debug_category_from_name!(CAT_META, "GST_META" ); |
592 | declare_debug_category_from_name!(CAT_LOCKING, "GST_LOCKING" ); |
593 | declare_debug_category_from_name!(CAT_CONTEXT, "GST_CONTEXT" ); |
594 | |
595 | #[macro_export ] |
596 | macro_rules! error( |
597 | ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { |
598 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Error, obj: $obj, $($args)*) |
599 | }}; |
600 | ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { |
601 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Error, imp: $imp, $($args)*) |
602 | }}; |
603 | ($cat:expr, id: $id:expr, $($args:tt)*) => { { |
604 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Error, id: $id, $($args)*) |
605 | }}; |
606 | ($cat:expr, $($args:tt)*) => { { |
607 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Error, $($args)*) |
608 | }}; |
609 | ); |
610 | |
611 | #[macro_export ] |
612 | macro_rules! warning( |
613 | ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { |
614 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Warning, obj: $obj, $($args)*) |
615 | }}; |
616 | ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { |
617 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Warning, imp: $imp, $($args)*) |
618 | }}; |
619 | ($cat:expr, id: $id:expr, $($args:tt)*) => { { |
620 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Warning, id: $id, $($args)*) |
621 | }}; |
622 | ($cat:expr, $($args:tt)*) => { { |
623 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Warning, $($args)*) |
624 | }}; |
625 | ); |
626 | |
627 | #[macro_export ] |
628 | macro_rules! fixme( |
629 | ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { |
630 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Fixme, obj: $obj, $($args)*) |
631 | }}; |
632 | ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { |
633 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Fixme, imp: $imp, $($args)*) |
634 | }}; |
635 | ($cat:expr, id: $id:expr, $($args:tt)*) => { { |
636 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Fixme, id: $id, $($args)*) |
637 | }}; |
638 | ($cat:expr, $($args:tt)*) => { { |
639 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Fixme, $($args)*) |
640 | }}; |
641 | ); |
642 | |
643 | #[macro_export ] |
644 | macro_rules! info( |
645 | ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { |
646 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Info, obj: $obj, $($args)*) |
647 | }}; |
648 | ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { |
649 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Info, imp: $imp, $($args)*) |
650 | }}; |
651 | ($cat:expr, id: $id:expr, $($args:tt)*) => { { |
652 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Info, id: $id, $($args)*) |
653 | }}; |
654 | ($cat:expr, $($args:tt)*) => { { |
655 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Info, $($args)*) |
656 | }}; |
657 | ); |
658 | |
659 | #[macro_export ] |
660 | macro_rules! debug( |
661 | ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { |
662 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Debug, obj: $obj, $($args)*) |
663 | }}; |
664 | ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { |
665 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Debug, imp: $imp, $($args)*) |
666 | }}; |
667 | ($cat:expr, id: $id:expr, $($args:tt)*) => { { |
668 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Debug, id: $id, $($args)*) |
669 | }}; |
670 | ($cat:expr, $($args:tt)*) => { { |
671 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Debug, $($args)*) |
672 | }}; |
673 | ); |
674 | |
675 | #[macro_export ] |
676 | macro_rules! log( |
677 | ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { |
678 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Log, obj: $obj, $($args)*) |
679 | }}; |
680 | ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { |
681 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Log, imp: $imp, $($args)*) |
682 | }}; |
683 | ($cat:expr, id: $id:expr, $($args:tt)*) => { { |
684 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Log, id: $id, $($args)*) |
685 | }}; |
686 | ($cat:expr, $($args:tt)*) => { { |
687 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Log, $($args)*) |
688 | }}; |
689 | ); |
690 | |
691 | #[macro_export ] |
692 | macro_rules! trace( |
693 | ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { |
694 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Trace, obj: $obj, $($args)*) |
695 | }}; |
696 | ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { |
697 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Trace, imp: $imp, $($args)*) |
698 | }}; |
699 | ($cat:expr, id: $id:expr, $($args:tt)*) => { { |
700 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Trace, id: $id, $($args)*) |
701 | }}; |
702 | ($cat:expr, $($args:tt)*) => { { |
703 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Trace, $($args)*) |
704 | }}; |
705 | ); |
706 | |
707 | #[macro_export ] |
708 | macro_rules! memdump( |
709 | ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { |
710 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Memdump, obj: $obj, $($args)*) |
711 | }}; |
712 | ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { |
713 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Memdump, imp: $imp, $($args)*) |
714 | }}; |
715 | ($cat:expr, id: $id:expr, $($args:tt)*) => { { |
716 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Memdump, id: $id, $($args)*) |
717 | }}; |
718 | ($cat:expr, $($args:tt)*) => { { |
719 | $crate::log_with_level!($cat, level: $crate::DebugLevel::Memdump, $($args)*) |
720 | }}; |
721 | ); |
722 | |
723 | #[macro_export ] |
724 | macro_rules! log_with_level( |
725 | ($cat:expr, level: $level:expr, obj: $obj:expr, $msg:literal) => { { |
726 | let cat = $cat.clone(); |
727 | |
728 | // Check the log level before using `format_args!` otherwise |
729 | // formatted arguments are evaluated even if we end up not logging. |
730 | #[allow(unused_unsafe)] |
731 | #[allow(clippy::redundant_closure_call)] |
732 | if cat.above_threshold($level) { |
733 | use $crate::glib::Cast; |
734 | |
735 | // FIXME: Once there's a function_name! macro that returns a string literal we can |
736 | // directly pass it as `&GStr` forward |
737 | |
738 | let obj = unsafe { $obj.unsafe_cast_ref::<$crate::glib::Object>() }; |
739 | let function_name = $crate::glib::function_name!(); |
740 | |
741 | // Check if formatting is necessary or not |
742 | // FIXME: This needs to be a closure because the return value of format_args!() can't |
743 | // be assigned to a variable |
744 | (|args: std::fmt::Arguments| { |
745 | if args.as_str().is_some() { |
746 | $crate::DebugCategory::log_literal_unfiltered( |
747 | cat, |
748 | Some(obj), |
749 | $level, |
750 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
751 | function_name, |
752 | line!(), |
753 | $crate::glib::gstr!($msg), |
754 | ) |
755 | } else { |
756 | $crate::DebugCategory::log_unfiltered( |
757 | cat, |
758 | Some(obj), |
759 | $level, |
760 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
761 | function_name, |
762 | line!(), |
763 | args, |
764 | ) |
765 | } |
766 | })(format_args!($msg)) |
767 | } |
768 | }}; |
769 | ($cat:expr, level: $level:expr, obj: $obj:expr, $($args:tt)*) => { { |
770 | let cat = $cat.clone(); |
771 | |
772 | // Check the log level before using `format_args!` otherwise |
773 | // formatted arguments are evaluated even if we end up not logging. |
774 | #[allow(unused_unsafe)] |
775 | if cat.above_threshold($level) { |
776 | use $crate::glib::Cast; |
777 | |
778 | // FIXME: Once there's a function_name! macro that returns a string literal we can |
779 | // directly pass it as `&GStr` forward |
780 | |
781 | let obj = unsafe { $obj.unsafe_cast_ref::<$crate::glib::Object>() }; |
782 | $crate::DebugCategory::log_unfiltered( |
783 | cat, |
784 | Some(obj), |
785 | $level, |
786 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
787 | $crate::glib::function_name!(), |
788 | line!(), |
789 | format_args!($($args)*), |
790 | ) |
791 | } |
792 | }}; |
793 | ($cat:expr, level: $level:expr, imp: $imp:expr, $msg:literal) => { { |
794 | let cat = $cat.clone(); |
795 | |
796 | // Check the log level before using `format_args!` otherwise |
797 | // formatted arguments are evaluated even if we end up not logging. |
798 | #[allow(unused_unsafe)] |
799 | #[allow(clippy::redundant_closure_call)] |
800 | if cat.above_threshold($level) { |
801 | use $crate::glib::Cast; |
802 | |
803 | // FIXME: Once there's a function_name! macro that returns a string literal we can |
804 | // directly pass it as `&GStr` forward |
805 | |
806 | let obj = $imp.obj(); |
807 | let obj = unsafe { obj.unsafe_cast_ref::<$crate::glib::Object>() }; |
808 | let function_name = $crate::glib::function_name!(); |
809 | |
810 | // Check if formatting is necessary or not |
811 | // FIXME: This needs to be a closure because the return value of format_args!() can't |
812 | // be assigned to a variable |
813 | (|args: std::fmt::Arguments| { |
814 | if args.as_str().is_some() { |
815 | $crate::DebugCategory::log_literal_unfiltered( |
816 | cat, |
817 | Some(obj), |
818 | $level, |
819 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
820 | function_name, |
821 | line!(), |
822 | $crate::glib::gstr!($msg), |
823 | ) |
824 | } else { |
825 | $crate::DebugCategory::log_unfiltered( |
826 | cat, |
827 | Some(obj), |
828 | $level, |
829 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
830 | function_name, |
831 | line!(), |
832 | args, |
833 | ) |
834 | } |
835 | })(format_args!($msg)) |
836 | } |
837 | }}; |
838 | ($cat:expr, level: $level:expr, imp: $imp:expr, $($args:tt)*) => { { |
839 | let cat = $cat.clone(); |
840 | |
841 | // Check the log level before using `format_args!` otherwise |
842 | // formatted arguments are evaluated even if we end up not logging. |
843 | #[allow(unused_unsafe)] |
844 | if cat.above_threshold($level) { |
845 | use $crate::glib::Cast; |
846 | |
847 | // FIXME: Once there's a function_name! macro that returns a string literal we can |
848 | // directly pass it as `&GStr` forward |
849 | |
850 | let obj = $imp.obj(); |
851 | let obj = unsafe { obj.unsafe_cast_ref::<$crate::glib::Object>() }; |
852 | $crate::DebugCategory::log_unfiltered( |
853 | cat, |
854 | Some(obj), |
855 | $level, |
856 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
857 | $crate::glib::function_name!(), |
858 | line!(), |
859 | format_args!($($args)*), |
860 | ) |
861 | } |
862 | }}; |
863 | ($cat:expr, level: $level:expr, id: $id:literal, $msg:literal) => { { |
864 | let cat = $cat.clone(); |
865 | |
866 | // Check the log level before using `format_args!` otherwise |
867 | // formatted arguments are evaluated even if we end up not logging. |
868 | #[allow(unused_unsafe)] |
869 | #[allow(clippy::redundant_closure_call)] |
870 | if cat.above_threshold($level) { |
871 | // FIXME: Once there's a function_name! macro that returns a string literal we can |
872 | // directly pass it as `&GStr` forward |
873 | |
874 | let function_name = $crate::glib::function_name!(); |
875 | |
876 | // Check if formatting is necessary or not |
877 | // FIXME: This needs to be a closure because the return value of format_args!() can't |
878 | // be assigned to a variable |
879 | (|args: std::fmt::Arguments| { |
880 | if args.as_str().is_some() { |
881 | $crate::DebugCategory::log_id_literal_unfiltered( |
882 | cat, |
883 | $crate::glib::gstr!($id), |
884 | $level, |
885 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
886 | function_name, |
887 | line!(), |
888 | $crate::glib::gstr!($msg), |
889 | ) |
890 | } else { |
891 | $crate::DebugCategory::log_id_unfiltered( |
892 | cat, |
893 | $crate::glib::gstr!($id), |
894 | $level, |
895 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
896 | function_name, |
897 | line!(), |
898 | args, |
899 | ) |
900 | } |
901 | })(format_args!($msg)) |
902 | } |
903 | }}; |
904 | ($cat:expr, level: $level:expr, id: $id:literal, $($args:tt)*) => { { |
905 | let cat = $cat.clone(); |
906 | |
907 | // Check the log level before using `format_args!` otherwise |
908 | // formatted arguments are evaluated even if we end up not logging. |
909 | #[allow(unused_unsafe)] |
910 | if cat.above_threshold($level) { |
911 | // FIXME: Once there's a function_name! macro that returns a string literal we can |
912 | // directly pass it as `&GStr` forward |
913 | |
914 | $crate::DebugCategory::log_id_unfiltered( |
915 | cat, |
916 | $crate::glib::gstr!($id), |
917 | $level, |
918 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
919 | $crate::glib::function_name!(), |
920 | line!(), |
921 | format_args!($($args)*), |
922 | ) |
923 | } |
924 | }}; |
925 | ($cat:expr, level: $level:expr, id: $id:expr, $msg:literal) => { { |
926 | let cat = $cat.clone(); |
927 | |
928 | // Check the log level before using `format_args!` otherwise |
929 | // formatted arguments are evaluated even if we end up not logging. |
930 | #[allow(unused_unsafe)] |
931 | #[allow(clippy::redundant_closure_call)] |
932 | if cat.above_threshold($level) { |
933 | // FIXME: Once there's a function_name! macro that returns a string literal we can |
934 | // directly pass it as `&GStr` forward |
935 | |
936 | let function_name = $crate::glib::function_name!(); |
937 | |
938 | // Check if formatting is necessary or not |
939 | // FIXME: This needs to be a closure because the return value of format_args!() can't |
940 | // be assigned to a variable |
941 | (|args: std::fmt::Arguments| { |
942 | if args.as_str().is_some() { |
943 | $crate::DebugCategory::log_id_literal_unfiltered( |
944 | cat, |
945 | $id, |
946 | $level, |
947 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
948 | function_name, |
949 | line!(), |
950 | $crate::glib::gstr!($msg), |
951 | ) |
952 | } else { |
953 | $crate::DebugCategory::log_id_unfiltered( |
954 | cat, |
955 | $id, |
956 | $level, |
957 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
958 | function_name, |
959 | line!(), |
960 | args, |
961 | ) |
962 | } |
963 | })(format_args!($msg)) |
964 | } |
965 | }}; |
966 | ($cat:expr, level: $level:expr, id: $id:expr, $($args:tt)*) => { { |
967 | let cat = $cat.clone(); |
968 | |
969 | // Check the log level before using `format_args!` otherwise |
970 | // formatted arguments are evaluated even if we end up not logging. |
971 | #[allow(unused_unsafe)] |
972 | if cat.above_threshold($level) { |
973 | // FIXME: Once there's a function_name! macro that returns a string literal we can |
974 | // directly pass it as `&GStr` forward |
975 | |
976 | $crate::DebugCategory::log_id_unfiltered( |
977 | cat, |
978 | $id, |
979 | $level, |
980 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
981 | $crate::glib::function_name!(), |
982 | line!(), |
983 | format_args!($($args)*), |
984 | ) |
985 | } |
986 | }}; |
987 | ($cat:expr, level: $level:expr, $msg:literal) => { { |
988 | let cat = $cat.clone(); |
989 | |
990 | // Check the log level before using `format_args!` otherwise |
991 | // formatted arguments are evaluated even if we end up not logging. |
992 | #[allow(unused_unsafe)] |
993 | #[allow(clippy::redundant_closure_call)] |
994 | if cat.above_threshold($level) { |
995 | // FIXME: Once there's a function_name! macro that returns a string literal we can |
996 | // directly pass it as `&GStr` forward |
997 | |
998 | let function_name = $crate::glib::function_name!(); |
999 | |
1000 | // Check if formatting is necessary or not |
1001 | // FIXME: This needs to be a closure because the return value of format_args!() can't |
1002 | // be assigned to a variable |
1003 | (|args: std::fmt::Arguments| { |
1004 | if args.as_str().is_some() { |
1005 | $crate::DebugCategory::log_literal_unfiltered( |
1006 | cat, |
1007 | None as Option<&$crate::glib::Object>, |
1008 | $level, |
1009 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
1010 | function_name, |
1011 | line!(), |
1012 | $crate::glib::gstr!($msg), |
1013 | ) |
1014 | } else { |
1015 | $crate::DebugCategory::log_unfiltered( |
1016 | cat, |
1017 | None as Option<&$crate::glib::Object>, |
1018 | $level, |
1019 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
1020 | function_name, |
1021 | line!(), |
1022 | args, |
1023 | ) |
1024 | } |
1025 | })(format_args!($msg)) |
1026 | } |
1027 | }}; |
1028 | ($cat:expr, level: $level:expr, $($args:tt)*) => { { |
1029 | let cat = $cat.clone(); |
1030 | |
1031 | // Check the log level before using `format_args!` otherwise |
1032 | // formatted arguments are evaluated even if we end up not logging. |
1033 | #[allow(unused_unsafe)] |
1034 | if cat.above_threshold($level) { |
1035 | // FIXME: Once there's a function_name! macro that returns a string literal we can |
1036 | // directly pass it as `&GStr` forward |
1037 | |
1038 | $crate::DebugCategory::log_unfiltered( |
1039 | cat, |
1040 | None as Option<&$crate::glib::Object>, |
1041 | $level, |
1042 | unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), " \0" ).as_bytes()) }, |
1043 | $crate::glib::function_name!(), |
1044 | line!(), |
1045 | format_args!($($args)*), |
1046 | ) |
1047 | } |
1048 | }}; |
1049 | ); |
1050 | |
1051 | unsafe extern "C" fn log_handler<T>( |
1052 | category: *mut ffi::GstDebugCategory, |
1053 | level: ffi::GstDebugLevel, |
1054 | file: *const c_char, |
1055 | function: *const c_char, |
1056 | line: i32, |
1057 | object: *mut glib::gobject_ffi::GObject, |
1058 | message: *mut ffi::GstDebugMessage, |
1059 | user_data: gpointer, |
1060 | ) where |
1061 | T: Fn( |
1062 | DebugCategory, |
1063 | DebugLevel, |
1064 | &glib::GStr, |
1065 | &glib::GStr, |
1066 | u32, |
1067 | Option<&LoggedObject>, |
1068 | &DebugMessage, |
1069 | ) + Send |
1070 | + Sync |
1071 | + 'static, |
1072 | { |
1073 | if category.is_null() { |
1074 | return; |
1075 | } |
1076 | let category: DebugCategory = DebugCategory(Some(ptr::NonNull::new_unchecked(ptr:category))); |
1077 | let level: DebugLevel = from_glib(val:level); |
1078 | let file: &GStr = glib::GStr::from_ptr(file); |
1079 | let function: &GStr = glib::GStr::from_ptr(function); |
1080 | let line: u32 = line as u32; |
1081 | let object: Option = ptr::NonNull::new(ptr:object).map(LoggedObject); |
1082 | let message: DebugMessage = DebugMessage(ptr::NonNull::new_unchecked(ptr:message)); |
1083 | let handler: &T = &*(user_data as *mut T); |
1084 | (handler)( |
1085 | category, |
1086 | level, |
1087 | file, |
1088 | function, |
1089 | line, |
1090 | object.as_ref(), |
1091 | &message, |
1092 | ); |
1093 | } |
1094 | |
1095 | unsafe extern "C" fn log_handler_data_free<T>(data: gpointer) { |
1096 | let data: Box = Box::from_raw(data as *mut T); |
1097 | drop(data); |
1098 | } |
1099 | |
1100 | #[derive (Debug)] |
1101 | pub struct DebugLogFunction(ptr::NonNull<std::os::raw::c_void>); |
1102 | |
1103 | // The contained pointer is never dereferenced and has no thread affinity. |
1104 | // It may be convenient to send it or share it between threads to allow cleaning |
1105 | // up log functions from other threads than the one that created it. |
1106 | unsafe impl Send for DebugLogFunction {} |
1107 | unsafe impl Sync for DebugLogFunction {} |
1108 | |
1109 | #[derive (Debug)] |
1110 | #[doc (alias = "GObject" )] |
1111 | pub struct LoggedObject(ptr::NonNull<glib::gobject_ffi::GObject>); |
1112 | |
1113 | impl LoggedObject { |
1114 | #[inline ] |
1115 | pub fn as_ptr(&self) -> *mut glib::gobject_ffi::GObject { |
1116 | self.0.as_ptr() |
1117 | } |
1118 | } |
1119 | |
1120 | impl fmt::Display for LoggedObject { |
1121 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
1122 | unsafe { |
1123 | let ptr = self.0.as_ptr(); |
1124 | let g_type_instance = &mut (*ptr).g_type_instance; |
1125 | if glib::gobject_ffi::g_type_check_instance_is_fundamentally_a( |
1126 | g_type_instance, |
1127 | glib::gobject_ffi::g_object_get_type(), |
1128 | ) != glib::ffi::GFALSE |
1129 | { |
1130 | let type_ = (*g_type_instance.g_class).g_type; |
1131 | |
1132 | if glib::gobject_ffi::g_type_is_a(type_, ffi::gst_pad_get_type()) |
1133 | != glib::ffi::GFALSE |
1134 | { |
1135 | let name_ptr = (*(ptr as *mut ffi::GstObject)).name; |
1136 | let name = if name_ptr.is_null() { |
1137 | "<null>" |
1138 | } else { |
1139 | CStr::from_ptr(name_ptr) |
1140 | .to_str() |
1141 | .unwrap_or("<invalid name>" ) |
1142 | }; |
1143 | |
1144 | let parent_ptr = (*(ptr as *mut ffi::GstObject)).parent; |
1145 | let parent_name = if parent_ptr.is_null() { |
1146 | "<null>" |
1147 | } else { |
1148 | let name_ptr = (*(parent_ptr)).name; |
1149 | if name_ptr.is_null() { |
1150 | "<null>" |
1151 | } else { |
1152 | CStr::from_ptr(name_ptr) |
1153 | .to_str() |
1154 | .unwrap_or("<invalid name>" ) |
1155 | } |
1156 | }; |
1157 | |
1158 | write!(f, " {parent_name}: {name}" ) |
1159 | } else if glib::gobject_ffi::g_type_is_a(type_, ffi::gst_object_get_type()) |
1160 | != glib::ffi::GFALSE |
1161 | { |
1162 | let name_ptr = (*(ptr as *mut ffi::GstObject)).name; |
1163 | let name = if name_ptr.is_null() { |
1164 | "<null>" |
1165 | } else { |
1166 | CStr::from_ptr(name_ptr) |
1167 | .to_str() |
1168 | .unwrap_or("<invalid name>" ) |
1169 | }; |
1170 | write!(f, " {name}" ) |
1171 | } else { |
1172 | let type_name = CStr::from_ptr(glib::gobject_ffi::g_type_name(type_)); |
1173 | write!( |
1174 | f, |
1175 | " {}: {:?}" , |
1176 | type_name.to_str().unwrap_or("<invalid type>" ), |
1177 | ptr |
1178 | ) |
1179 | } |
1180 | } else { |
1181 | write!(f, " {ptr:?}" ) |
1182 | } |
1183 | } |
1184 | } |
1185 | } |
1186 | |
1187 | #[doc (alias = "gst_debug_add_log_function" )] |
1188 | pub fn debug_add_log_function<T>(function: T) -> DebugLogFunction |
1189 | where |
1190 | T: Fn( |
1191 | DebugCategory, |
1192 | DebugLevel, |
1193 | &glib::GStr, |
1194 | &glib::GStr, |
1195 | u32, |
1196 | Option<&LoggedObject>, |
1197 | &DebugMessage, |
1198 | ) + Send |
1199 | + Sync |
1200 | + 'static, |
1201 | { |
1202 | skip_assert_initialized!(); |
1203 | unsafe { |
1204 | let user_data: Box = Box::new(function); |
1205 | let user_data_ptr: *mut c_void = Box::into_raw(user_data) as gpointer; |
1206 | ffi::gst_debug_add_log_function( |
1207 | func:Some(log_handler::<T>), |
1208 | user_data_ptr, |
1209 | notify:Some(log_handler_data_free::<T>), |
1210 | ); |
1211 | DebugLogFunction(ptr::NonNull::new_unchecked(user_data_ptr)) |
1212 | } |
1213 | } |
1214 | |
1215 | pub fn debug_remove_default_log_function() { |
1216 | skip_assert_initialized!(); |
1217 | unsafe { |
1218 | ffi::gst_debug_remove_log_function(func:None); |
1219 | } |
1220 | } |
1221 | |
1222 | #[doc (alias = "gst_debug_remove_log_function_by_data" )] |
1223 | pub fn debug_remove_log_function(log_fn: DebugLogFunction) { |
1224 | skip_assert_initialized!(); |
1225 | unsafe { |
1226 | ffi::gst_debug_remove_log_function_by_data(log_fn.0.as_ptr()); |
1227 | } |
1228 | } |
1229 | |
1230 | #[cfg (test)] |
1231 | mod tests { |
1232 | use std::sync::{mpsc, Arc, Mutex}; |
1233 | |
1234 | use super::*; |
1235 | |
1236 | #[test ] |
1237 | #[doc (alias = "get_existing" )] |
1238 | fn existing() { |
1239 | crate::init().unwrap(); |
1240 | |
1241 | let perf_cat = DebugCategory::get("GST_PERFORMANCE" ) |
1242 | .expect("Unable to find `DebugCategory` with name \"GST_PERFORMANCE \"" ); |
1243 | assert_eq!(perf_cat.name(), CAT_PERFORMANCE.name()); |
1244 | } |
1245 | |
1246 | #[test ] |
1247 | fn all() { |
1248 | crate::init().unwrap(); |
1249 | |
1250 | assert!(DebugCategory::all_categories() |
1251 | .iter() |
1252 | .any(|c| c.name() == "GST_PERFORMANCE" )); |
1253 | } |
1254 | |
1255 | #[test ] |
1256 | fn new_and_log() { |
1257 | crate::init().unwrap(); |
1258 | |
1259 | let cat = DebugCategory::new( |
1260 | "test-cat" , |
1261 | crate::DebugColorFlags::empty(), |
1262 | Some("some debug category" ), |
1263 | ); |
1264 | |
1265 | error!(cat, "meh" ); |
1266 | warning!(cat, "meh" ); |
1267 | fixme!(cat, "meh" ); |
1268 | info!(cat, "meh" ); |
1269 | debug!(cat, "meh" ); |
1270 | log!(cat, "meh" ); |
1271 | trace!(cat, "meh" ); |
1272 | memdump!(cat, "meh" ); |
1273 | |
1274 | let obj = crate::Bin::with_name("meh" ); |
1275 | |
1276 | error!(cat, obj: &obj, "meh" ); |
1277 | warning!(cat, obj: &obj, "meh" ); |
1278 | fixme!(cat, obj: &obj, "meh" ); |
1279 | info!(cat, obj: &obj, "meh" ); |
1280 | debug!(cat, obj: &obj, "meh" ); |
1281 | log!(cat, obj: &obj, "meh" ); |
1282 | trace!(cat, obj: &obj, "meh" ); |
1283 | memdump!(cat, obj: &obj, "meh" ); |
1284 | |
1285 | error!(cat, obj: obj, "meh" ); |
1286 | warning!(cat, obj: obj, "meh" ); |
1287 | fixme!(cat, obj: obj, "meh" ); |
1288 | info!(cat, obj: obj, "meh" ); |
1289 | debug!(cat, obj: obj, "meh" ); |
1290 | log!(cat, obj: obj, "meh" ); |
1291 | trace!(cat, obj: obj, "meh" ); |
1292 | memdump!(cat, obj: obj, "meh" ); |
1293 | } |
1294 | |
1295 | #[test ] |
1296 | fn log_handler() { |
1297 | crate::init().unwrap(); |
1298 | |
1299 | let cat = DebugCategory::new( |
1300 | "test-cat-log" , |
1301 | crate::DebugColorFlags::empty(), |
1302 | Some("some debug category" ), |
1303 | ); |
1304 | cat.set_threshold(DebugLevel::Info); |
1305 | let obj = crate::Bin::with_name("meh" ); |
1306 | |
1307 | let (sender, receiver) = mpsc::channel(); |
1308 | |
1309 | let sender = Arc::new(Mutex::new(sender)); |
1310 | |
1311 | let handler = move |category: DebugCategory, |
1312 | level: DebugLevel, |
1313 | _file: &glib::GStr, |
1314 | _function: &glib::GStr, |
1315 | _line: u32, |
1316 | _object: Option<&LoggedObject>, |
1317 | message: &DebugMessage| { |
1318 | let cat = DebugCategory::get("test-cat-log" ).unwrap(); |
1319 | |
1320 | if category != cat { |
1321 | // This test can run in parallel with other tests, including new_and_log above. |
1322 | // We cannot be certain we only see our own messages. |
1323 | return; |
1324 | } |
1325 | |
1326 | assert_eq!(level, DebugLevel::Info); |
1327 | assert_eq!(message.get().unwrap().as_ref(), "meh" ); |
1328 | let _ = sender.lock().unwrap().send(()); |
1329 | }; |
1330 | |
1331 | debug_remove_default_log_function(); |
1332 | let log_fn = debug_add_log_function(handler); |
1333 | info!(cat, obj: &obj, "meh" ); |
1334 | |
1335 | receiver.recv().unwrap(); |
1336 | |
1337 | debug_remove_log_function(log_fn); |
1338 | |
1339 | info!(cat, obj: &obj, "meh2" ); |
1340 | assert!(receiver.recv().is_err()); |
1341 | } |
1342 | |
1343 | #[test ] |
1344 | fn no_argument_evaluation() { |
1345 | crate::init().unwrap(); |
1346 | |
1347 | let cat = DebugCategory::new( |
1348 | "no_argument_evaluation" , |
1349 | crate::DebugColorFlags::empty(), |
1350 | Some("No Argument Evaluation debug category" ), |
1351 | ); |
1352 | |
1353 | let mut arg_evaluated = false; |
1354 | trace!(cat, " {}" , { |
1355 | arg_evaluated = true; |
1356 | "trace log" |
1357 | }); |
1358 | |
1359 | assert!(!arg_evaluated); |
1360 | } |
1361 | |
1362 | #[cfg (feature = "v1_22" )] |
1363 | #[test ] |
1364 | fn id_logging() { |
1365 | crate::init().unwrap(); |
1366 | |
1367 | let cat = DebugCategory::new( |
1368 | "log_with_id_test_category" , |
1369 | crate::DebugColorFlags::empty(), |
1370 | Some("Blablabla" ), |
1371 | ); |
1372 | |
1373 | trace!(cat, id: "123" , "test" ); |
1374 | trace!(cat, id: glib::GString::from("123" ), "test" ); |
1375 | trace!(cat, id: &glib::GString::from("123" ), "test" ); |
1376 | } |
1377 | } |
1378 | |