1use std::{borrow::Cow, ffi::CStr, fmt, ptr};
4
5use glib::{ffi::gpointer, prelude::*, translate::*};
6use libc::c_char;
7#[cfg(feature = "log")]
8use log;
9use once_cell::sync::Lazy;
10
11use crate::{ffi, DebugLevel};
12
13pub use crate::auto::functions::debug_add_ring_buffer_logger as add_ring_buffer_logger;
15pub use crate::auto::functions::debug_get_default_threshold as get_default_threshold;
16pub use crate::auto::functions::debug_get_stack_trace as get_stack_trace;
17pub use crate::auto::functions::debug_is_active as is_active;
18pub use crate::auto::functions::debug_is_colored as is_colored;
19pub use crate::auto::functions::debug_print_stack_trace as print_stack_trace;
20pub use crate::auto::functions::debug_remove_ring_buffer_logger as remove_ring_buffer_logger;
21pub use crate::auto::functions::debug_ring_buffer_logger_get_logs as ring_buffer_logger_get_logs;
22pub use crate::auto::functions::debug_set_active as set_active;
23pub use crate::auto::functions::debug_set_colored as set_colored;
24pub use crate::auto::functions::debug_set_default_threshold as set_default_threshold;
25pub use crate::auto::functions::debug_set_threshold_for_name as set_threshold_for_name;
26pub use crate::auto::functions::debug_set_threshold_from_string as set_threshold_from_string;
27pub use crate::auto::functions::debug_unset_threshold_for_name as unset_threshold_for_name;
28
29#[derive(PartialEq, Eq)]
30#[doc(alias = "GstDebugMessage")]
31pub struct DebugMessage(ptr::NonNull<ffi::GstDebugMessage>);
32
33impl fmt::Debug for DebugMessage {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 f.debug_tuple("DebugMessage").field(&self.get()).finish()
36 }
37}
38
39impl DebugMessage {
40 #[doc(alias = "gst_debug_message_get")]
47 #[inline]
48 pub fn get(&self) -> Option<Cow<glib::GStr>> {
49 unsafe {
50 let message = ffi::gst_debug_message_get(self.0.as_ptr());
51
52 if message.is_null() {
53 None
54 } else {
55 Some(glib::GStr::from_ptr_lossy(message))
56 }
57 }
58 }
59
60 #[cfg(feature = "v1_22")]
67 #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
68 #[doc(alias = "gst_debug_message_get_id")]
69 #[inline]
70 pub fn id(&self) -> Option<&glib::GStr> {
71 unsafe {
72 let id = ffi::gst_debug_message_get_id(self.0.as_ptr());
73
74 if id.is_null() {
75 None
76 } else {
77 Some(glib::GStr::from_ptr(id))
78 }
79 }
80 }
81
82 #[inline]
83 pub fn as_ptr(&self) -> *mut ffi::GstDebugMessage {
84 self.0.as_ptr()
85 }
86}
87
88#[derive(PartialEq, Eq, Clone, Copy, Hash)]
91#[doc(alias = "GstDebugCategory")]
92#[repr(transparent)]
93pub struct DebugCategory(Option<ptr::NonNull<ffi::GstDebugCategory>>);
94
95impl DebugCategory {
96 #[doc(alias = "gst_debug_category_new")]
97 #[doc(alias = "GST_DEBUG_CATEGORY")]
98 #[doc(alias = "GST_DEBUG_CATEGORY_INIT")]
99 pub fn new(
100 name: &str,
101 color: crate::DebugColorFlags,
102 description: Option<&str>,
103 ) -> DebugCategory {
104 skip_assert_initialized!();
105 extern "C" {
106 fn _gst_debug_category_new(
107 name: *const c_char,
108 color: ffi::GstDebugColorFlags,
109 description: *const c_char,
110 ) -> *mut ffi::GstDebugCategory;
111 }
112
113 unsafe {
115 let ptr = name.run_with_gstr(|name| {
116 description.run_with_gstr(|description| {
117 _gst_debug_category_new(
118 name.to_glib_none().0,
119 color.into_glib(),
120 description.to_glib_none().0,
121 )
122 })
123 });
124
125 DebugCategory(ptr::NonNull::new(ptr))
127 }
128 }
129
130 #[doc(alias = "gst_debug_get_category")]
131 #[inline]
132 pub fn get(name: &str) -> Option<DebugCategory> {
133 skip_assert_initialized!();
134 unsafe {
135 extern "C" {
136 fn _gst_debug_get_category(name: *const c_char) -> *mut ffi::GstDebugCategory;
137 }
138
139 let cat = name.run_with_gstr(|name| _gst_debug_get_category(name.to_glib_none().0));
140
141 if cat.is_null() {
142 None
143 } else {
144 Some(DebugCategory(Some(ptr::NonNull::new_unchecked(cat))))
145 }
146 }
147 }
148
149 #[doc(alias = "get_threshold")]
155 #[doc(alias = "gst_debug_category_get_threshold")]
156 #[inline]
157 pub fn threshold(self) -> crate::DebugLevel {
158 match self.0 {
159 Some(cat) => unsafe { from_glib(cat.as_ref().threshold) },
160 None => crate::DebugLevel::None,
161 }
162 }
163
164 #[doc(alias = "gst_debug_category_set_threshold")]
173 #[inline]
174 pub fn set_threshold(self, threshold: crate::DebugLevel) {
175 if let Some(cat) = self.0 {
176 unsafe { ffi::gst_debug_category_set_threshold(cat.as_ptr(), threshold.into_glib()) }
177 }
178 }
179
180 #[doc(alias = "gst_debug_category_reset_threshold")]
186 #[inline]
187 pub fn reset_threshold(self) {
188 if let Some(cat) = self.0 {
189 unsafe { ffi::gst_debug_category_reset_threshold(cat.as_ptr()) }
190 }
191 }
192
193 #[inline]
194 pub fn above_threshold(self, level: crate::DebugLevel) -> bool {
195 match self.0 {
196 Some(cat) => unsafe { cat.as_ref().threshold >= level.into_glib() },
197 None => false,
198 }
199 }
200
201 #[doc(alias = "get_color")]
208 #[doc(alias = "gst_debug_category_get_color")]
209 #[inline]
210 pub fn color(self) -> crate::DebugColorFlags {
211 match self.0 {
212 Some(cat) => unsafe { from_glib(cat.as_ref().color) },
213 None => crate::DebugColorFlags::empty(),
214 }
215 }
216
217 #[doc(alias = "get_name")]
223 #[doc(alias = "gst_debug_category_get_name")]
224 #[inline]
225 pub fn name<'a>(self) -> &'a str {
226 match self.0 {
227 Some(cat) => unsafe { CStr::from_ptr(cat.as_ref().name).to_str().unwrap() },
228 None => "",
229 }
230 }
231
232 #[doc(alias = "get_description")]
238 #[doc(alias = "gst_debug_category_get_description")]
239 #[inline]
240 pub fn description<'a>(self) -> Option<&'a str> {
241 let cat = self.0?;
242
243 unsafe {
244 let ptr = cat.as_ref().description;
245
246 if ptr.is_null() {
247 None
248 } else {
249 Some(CStr::from_ptr(ptr).to_str().unwrap())
250 }
251 }
252 }
253
254 #[inline]
255 #[doc(alias = "gst_debug_log")]
256 #[doc(alias = "gst_debug_log_literal")]
257 pub fn log(
258 self,
259 obj: Option<&impl IsA<glib::Object>>,
260 level: crate::DebugLevel,
261 file: &glib::GStr,
262 function: &str,
263 line: u32,
264 args: fmt::Arguments,
265 ) {
266 if !self.above_threshold(level) {
267 return;
268 }
269
270 self.log_unfiltered_internal(
271 obj.map(|obj| obj.as_ref()),
272 level,
273 file,
274 function,
275 line,
276 args,
277 )
278 }
279
280 #[inline]
281 #[doc(alias = "gst_debug_log_literal")]
282 pub fn log_literal(
283 self,
284 obj: Option<&impl IsA<glib::Object>>,
285 level: crate::DebugLevel,
286 file: &glib::GStr,
287 function: &str,
288 line: u32,
289 msg: &glib::GStr,
290 ) {
291 if !self.above_threshold(level) {
292 return;
293 }
294
295 self.log_literal_unfiltered_internal(
296 obj.map(|obj| obj.as_ref()),
297 level,
298 file,
299 function,
300 line,
301 msg,
302 )
303 }
304
305 #[inline]
308 #[doc(alias = "gst_debug_log")]
309 pub fn log_unfiltered(
310 self,
311 obj: Option<&impl IsA<glib::Object>>,
312 level: crate::DebugLevel,
313 file: &glib::GStr,
314 function: &str,
315 line: u32,
316 args: fmt::Arguments,
317 ) {
318 self.log_unfiltered_internal(
319 obj.map(|obj| obj.as_ref()),
320 level,
321 file,
322 function,
323 line,
324 args,
325 )
326 }
327
328 #[inline]
331 #[doc(alias = "gst_debug_log_literal")]
332 pub fn log_literal_unfiltered(
333 self,
334 obj: Option<&impl IsA<glib::Object>>,
335 level: crate::DebugLevel,
336 file: &glib::GStr,
337 function: &str,
338 line: u32,
339 msg: &glib::GStr,
340 ) {
341 self.log_literal_unfiltered_internal(
342 obj.map(|obj| obj.as_ref()),
343 level,
344 file,
345 function,
346 line,
347 msg,
348 )
349 }
350
351 #[inline(never)]
352 fn log_unfiltered_internal(
353 self,
354 obj: Option<&glib::Object>,
355 level: crate::DebugLevel,
356 file: &glib::GStr,
357 function: &str,
358 line: u32,
359 args: fmt::Arguments,
360 ) {
361 let mut w = smallvec::SmallVec::<[u8; 256]>::new();
362
363 if std::io::Write::write_fmt(&mut w, args).is_err() {
365 return;
366 }
367 w.push(0);
368
369 self.log_literal_unfiltered_internal(obj, level, file, function, line, unsafe {
370 glib::GStr::from_utf8_with_nul_unchecked(&w)
371 });
372 }
373
374 #[inline(never)]
375 fn log_literal_unfiltered_internal(
376 self,
377 obj: Option<&glib::Object>,
378 level: crate::DebugLevel,
379 file: &glib::GStr,
380 function: &str,
381 line: u32,
382 msg: &glib::GStr,
383 ) {
384 let cat = match self.0 {
385 Some(cat) => cat,
386 None => return,
387 };
388
389 let obj_ptr = match obj {
390 Some(obj) => obj.as_ptr(),
391 None => ptr::null_mut(),
392 };
393
394 function.run_with_gstr(|function| {
395 #[cfg(feature = "v1_20")]
396 unsafe {
397 ffi::gst_debug_log_literal(
398 cat.as_ptr(),
399 level.into_glib(),
400 file.as_ptr(),
401 function.as_ptr(),
402 line as i32,
403 obj_ptr,
404 msg.as_ptr(),
405 );
406 }
407 #[cfg(not(feature = "v1_20"))]
408 unsafe {
409 ffi::gst_debug_log(
410 cat.as_ptr(),
411 level.into_glib(),
412 file.as_ptr(),
413 function.as_ptr(),
414 line as i32,
415 obj_ptr,
416 b"%s\0".as_ptr() as *const _,
417 msg.as_ptr(),
418 );
419 }
420 });
421 }
422
423 #[cfg(feature = "v1_22")]
424 #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
425 #[inline]
426 #[doc(alias = "gst_debug_log_id")]
427 pub fn log_id(
428 self,
429 id: impl AsRef<glib::GStr>,
430 level: crate::DebugLevel,
431 file: &glib::GStr,
432 function: &str,
433 line: u32,
434 args: fmt::Arguments,
435 ) {
436 if !self.above_threshold(level) {
437 return;
438 }
439
440 self.log_id_unfiltered_internal(id.as_ref(), level, file, function, line, args);
441 }
442
443 #[cfg(feature = "v1_22")]
444 #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
445 #[inline]
446 #[doc(alias = "gst_debug_log_id_literal")]
447 pub fn log_id_literal(
448 self,
449 id: impl AsRef<glib::GStr>,
450 level: crate::DebugLevel,
451 file: &glib::GStr,
452 function: &str,
453 line: u32,
454 msg: &glib::GStr,
455 ) {
456 if !self.above_threshold(level) {
457 return;
458 }
459
460 self.log_id_literal_unfiltered_internal(id.as_ref(), level, file, function, line, msg);
461 }
462
463 #[cfg(feature = "v1_22")]
464 #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
465 #[inline]
468 #[doc(alias = "gst_debug_log_id")]
469 pub fn log_id_unfiltered(
470 self,
471 id: impl AsRef<glib::GStr>,
472 level: crate::DebugLevel,
473 file: &glib::GStr,
474 function: &str,
475 line: u32,
476 args: fmt::Arguments,
477 ) {
478 self.log_id_unfiltered_internal(id.as_ref(), level, file, function, line, args)
479 }
480
481 #[cfg(feature = "v1_22")]
482 #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
483 #[inline]
486 #[doc(alias = "gst_debug_log_id_literal")]
487 pub fn log_id_literal_unfiltered(
488 self,
489 id: impl AsRef<glib::GStr>,
490 level: crate::DebugLevel,
491 file: &glib::GStr,
492 function: &str,
493 line: u32,
494 msg: &glib::GStr,
495 ) {
496 self.log_id_literal_unfiltered_internal(id.as_ref(), level, file, function, line, msg)
497 }
498
499 #[cfg(feature = "v1_22")]
500 #[inline(never)]
501 fn log_id_unfiltered_internal(
502 self,
503 id: &glib::GStr,
504 level: crate::DebugLevel,
505 file: &glib::GStr,
506 function: &str,
507 line: u32,
508 args: fmt::Arguments,
509 ) {
510 let mut w = smallvec::SmallVec::<[u8; 256]>::new();
511
512 if std::io::Write::write_fmt(&mut w, args).is_err() {
514 return;
515 }
516 w.push(0);
517
518 self.log_id_literal_unfiltered_internal(id, level, file, function, line, unsafe {
519 glib::GStr::from_utf8_with_nul_unchecked(&w)
520 });
521 }
522
523 #[cfg(feature = "v1_22")]
524 #[inline(never)]
525 fn log_id_literal_unfiltered_internal(
526 self,
527 id: &glib::GStr,
528 level: crate::DebugLevel,
529 file: &glib::GStr,
530 function: &str,
531 line: u32,
532 msg: &glib::GStr,
533 ) {
534 let cat = match self.0 {
535 Some(cat) => cat,
536 None => return,
537 };
538
539 function.run_with_gstr(|function| unsafe {
540 ffi::gst_debug_log_id_literal(
541 cat.as_ptr(),
542 level.into_glib(),
543 file.as_ptr(),
544 function.as_ptr(),
545 line as i32,
546 id.as_ptr(),
547 msg.as_ptr(),
548 );
549 });
550 }
551
552 #[doc(alias = "get_all_categories")]
553 #[doc(alias = "gst_debug_get_all_categories")]
554 #[inline]
555 pub fn all_categories() -> glib::SList<DebugCategory> {
556 unsafe { glib::SList::from_glib_container(ffi::gst_debug_get_all_categories()) }
557 }
558
559 #[cfg(feature = "v1_18")]
560 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
561 #[doc(alias = "gst_debug_log_get_line")]
562 #[inline]
563 pub fn get_line(
564 &self,
565 level: crate::DebugLevel,
566 file: &glib::GStr,
567 function: &glib::GStr,
568 line: u32,
569 object: Option<&LoggedObject>,
570 message: &DebugMessage,
571 ) -> Option<glib::GString> {
572 let cat = self.0?;
573
574 unsafe {
575 from_glib_full(ffi::gst_debug_log_get_line(
576 cat.as_ptr(),
577 level.into_glib(),
578 file.as_ptr(),
579 function.as_ptr(),
580 line as i32,
581 object.map(|o| o.as_ptr()).unwrap_or(ptr::null_mut()),
582 message.0.as_ptr(),
583 ))
584 }
585 }
586
587 #[inline]
588 pub fn as_ptr(&self) -> *mut ffi::GstDebugCategory {
589 self.0.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut())
590 }
591}
592
593unsafe impl Sync for DebugCategory {}
594unsafe impl Send for DebugCategory {}
595
596impl fmt::Debug for DebugCategory {
597 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
598 f.debug_tuple("DebugCategory").field(&self.name()).finish()
599 }
600}
601
602impl GlibPtrDefault for DebugCategory {
603 type GlibType = *mut ffi::GstDebugCategory;
604}
605
606unsafe impl TransparentPtrType for DebugCategory {}
607
608impl FromGlibPtrNone<*mut ffi::GstDebugCategory> for DebugCategory {
609 #[inline]
610 unsafe fn from_glib_none(ptr: *mut ffi::GstDebugCategory) -> Self {
611 debug_assert!(!ptr.is_null());
612 DebugCategory(Some(ptr::NonNull::new_unchecked(ptr)))
613 }
614}
615
616impl FromGlibPtrFull<*mut ffi::GstDebugCategory> for DebugCategory {
617 #[inline]
618 unsafe fn from_glib_full(ptr: *mut ffi::GstDebugCategory) -> Self {
619 debug_assert!(!ptr.is_null());
620 DebugCategory(Some(ptr::NonNull::new_unchecked(ptr)))
621 }
622}
623
624pub static CAT_RUST: Lazy<DebugCategory> = Lazy::new(|| {
625 DebugCategory::new(
626 "GST_RUST",
627 crate::DebugColorFlags::UNDERLINE,
628 Some("GStreamer's Rust binding core"),
629 )
630});
631
632macro_rules! declare_debug_category_from_name(
633 ($cat:ident, $cat_name:expr) => (
634 pub static $cat: Lazy<DebugCategory> = Lazy::new(|| DebugCategory::get($cat_name)
635 .expect(&format!("Unable to find `DebugCategory` with name {}", $cat_name)));
636 );
637);
638
639declare_debug_category_from_name!(CAT_DEFAULT, "default");
640declare_debug_category_from_name!(CAT_GST_INIT, "GST_INIT");
641declare_debug_category_from_name!(CAT_MEMORY, "GST_MEMORY");
642declare_debug_category_from_name!(CAT_PARENTAGE, "GST_PARENTAGE");
643declare_debug_category_from_name!(CAT_STATES, "GST_STATES");
644declare_debug_category_from_name!(CAT_SCHEDULING, "GST_SCHEDULING");
645declare_debug_category_from_name!(CAT_BUFFER, "GST_BUFFER");
646declare_debug_category_from_name!(CAT_BUFFER_LIST, "GST_BUFFER_LIST");
647declare_debug_category_from_name!(CAT_BUS, "GST_BUS");
648declare_debug_category_from_name!(CAT_CAPS, "GST_CAPS");
649declare_debug_category_from_name!(CAT_CLOCK, "GST_CLOCK");
650declare_debug_category_from_name!(CAT_ELEMENT_PADS, "GST_ELEMENT_PADS");
651declare_debug_category_from_name!(CAT_PADS, "GST_PADS");
652declare_debug_category_from_name!(CAT_PERFORMANCE, "GST_PERFORMANCE");
653declare_debug_category_from_name!(CAT_PIPELINE, "GST_PIPELINE");
654declare_debug_category_from_name!(CAT_PLUGIN_LOADING, "GST_PLUGIN_LOADING");
655declare_debug_category_from_name!(CAT_PLUGIN_INFO, "GST_PLUGIN_INFO");
656declare_debug_category_from_name!(CAT_PROPERTIES, "GST_PROPERTIES");
657declare_debug_category_from_name!(CAT_NEGOTIATION, "GST_NEGOTIATION");
658declare_debug_category_from_name!(CAT_REFCOUNTING, "GST_REFCOUNTING");
659declare_debug_category_from_name!(CAT_ERROR_SYSTEM, "GST_ERROR_SYSTEM");
660declare_debug_category_from_name!(CAT_EVENT, "GST_EVENT");
661declare_debug_category_from_name!(CAT_MESSAGE, "GST_MESSAGE");
662declare_debug_category_from_name!(CAT_PARAMS, "GST_PARAMS");
663declare_debug_category_from_name!(CAT_CALL_TRACE, "GST_CALL_TRACE");
664declare_debug_category_from_name!(CAT_SIGNAL, "GST_SIGNAL");
665declare_debug_category_from_name!(CAT_PROBE, "GST_PROBE");
666declare_debug_category_from_name!(CAT_REGISTRY, "GST_REGISTRY");
667declare_debug_category_from_name!(CAT_QOS, "GST_QOS");
668declare_debug_category_from_name!(CAT_META, "GST_META");
669declare_debug_category_from_name!(CAT_LOCKING, "GST_LOCKING");
670declare_debug_category_from_name!(CAT_CONTEXT, "GST_CONTEXT");
671
672#[macro_export]
673macro_rules! error(
674 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
675 $crate::log_with_level!($cat, $crate::DebugLevel::Error, obj = $obj, $($args)*)
676 }};
677 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
678 $crate::log_with_level!($cat, $crate::DebugLevel::Error, imp = $imp, $($args)*)
679 }};
680 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
681 $crate::log_with_level!($cat, $crate::DebugLevel::Error, id = $id, $($args)*)
682 }};
683
684 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
685 {
686 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
687 macro_rules! error(
688 () => {}
689 );
690 error!();
691 }
692 $crate::log_with_level!($cat, $crate::DebugLevel::Error, obj = $obj, $($args)*)
693 }};
694 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
695 {
696 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
697 macro_rules! error(
698 () => {}
699 );
700 error!();
701 }
702 $crate::log_with_level!($cat, $crate::DebugLevel::Error, imp = $imp, $($args)*)
703 }};
704 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
705 {
706 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"]
707 macro_rules! error(
708 () => {}
709 );
710 error!();
711 }
712 $crate::log_with_level!($cat, $crate::DebugLevel::Error, id = $id, $($args)*)
713 }};
714 ($cat:expr, $($args:tt)*) => { {
715 $crate::log_with_level!($cat, $crate::DebugLevel::Error, $($args)*)
716 }};
717);
718
719#[macro_export]
720macro_rules! warning(
721 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
722 $crate::log_with_level!($cat, $crate::DebugLevel::Warning, obj = $obj, $($args)*)
723 }};
724 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
725 $crate::log_with_level!($cat, $crate::DebugLevel::Warning, imp = $imp, $($args)*)
726 }};
727 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
728 $crate::log_with_level!($cat, $crate::DebugLevel::Warning, id = $id, $($args)*)
729 }};
730
731 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
732 {
733 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
734 macro_rules! warning(
735 () => {}
736 );
737 warning!();
738 }
739 $crate::log_with_level!($cat, $crate::DebugLevel::Warning, obj = $obj, $($args)*)
740 }};
741 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
742 {
743 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
744 macro_rules! warning(
745 () => {}
746 );
747 warning!();
748 }
749 $crate::log_with_level!($cat, $crate::DebugLevel::Warning, imp = $imp, $($args)*)
750 }};
751 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
752 {
753 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"]
754 macro_rules! warning(
755 () => {}
756 );
757 warning!();
758 }
759 $crate::log_with_level!($cat, $crate::DebugLevel::Warning, id = $id, $($args)*)
760 }};
761 ($cat:expr, $($args:tt)*) => { {
762 $crate::log_with_level!($cat, $crate::DebugLevel::Warning, $($args)*)
763 }};
764);
765
766#[macro_export]
767macro_rules! fixme(
768 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
769 $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, obj = $obj, $($args)*)
770 }};
771 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
772 $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, imp = $imp, $($args)*)
773 }};
774 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
775 $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, id = $id, $($args)*)
776 }};
777
778 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
779 {
780 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
781 macro_rules! fixme(
782 () => {}
783 );
784 fixme!();
785 }
786 $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, obj = $obj, $($args)*)
787 }};
788 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
789 {
790 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
791 macro_rules! fixme(
792 () => {}
793 );
794 fixme!();
795 }
796 $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, imp = $imp, $($args)*)
797 }};
798 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
799 {
800 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"]
801 macro_rules! fixme(
802 () => {}
803 );
804 fixme!();
805 }
806 $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, id = $id, $($args)*)
807 }};
808 ($cat:expr, $($args:tt)*) => { {
809 $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, $($args)*)
810 }};
811);
812
813#[macro_export]
814macro_rules! info(
815 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
816 $crate::log_with_level!($cat, $crate::DebugLevel::Info, obj = $obj, $($args)*)
817 }};
818 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
819 $crate::log_with_level!($cat, $crate::DebugLevel::Info, imp = $imp, $($args)*)
820 }};
821 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
822 $crate::log_with_level!($cat, $crate::DebugLevel::Info, id = $id, $($args)*)
823 }};
824
825 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
826 {
827 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
828 macro_rules! info(
829 () => {}
830 );
831 info!();
832 }
833 $crate::log_with_level!($cat, $crate::DebugLevel::Info, obj = $obj, $($args)*)
834 }};
835 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
836 {
837 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
838 macro_rules! info(
839 () => {}
840 );
841 info!();
842 }
843 $crate::log_with_level!($cat, $crate::DebugLevel::Info, imp = $imp, $($args)*)
844 }};
845 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
846 {
847 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"]
848 macro_rules! info(
849 () => {}
850 );
851 info!();
852 }
853 $crate::log_with_level!($cat, $crate::DebugLevel::Info, id = $id, $($args)*)
854 }};
855 ($cat:expr, $($args:tt)*) => { {
856 $crate::log_with_level!($cat, $crate::DebugLevel::Info, $($args)*)
857 }};
858);
859
860#[macro_export]
861macro_rules! debug(
862 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
863 $crate::log_with_level!($cat, $crate::DebugLevel::Debug, obj = $obj, $($args)*)
864 }};
865 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
866 $crate::log_with_level!($cat, $crate::DebugLevel::Debug, imp = $imp, $($args)*)
867 }};
868 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
869 $crate::log_with_level!($cat, $crate::DebugLevel::Debug, id = $id, $($args)*)
870 }};
871
872 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
873 {
874 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
875 macro_rules! debug(
876 () => {}
877 );
878 debug!();
879 }
880 $crate::log_with_level!($cat, $crate::DebugLevel::Debug, obj = $obj, $($args)*)
881 }};
882 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
883 {
884 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
885 macro_rules! debug(
886 () => {}
887 );
888 debug!();
889 }
890 $crate::log_with_level!($cat, $crate::DebugLevel::Debug, imp = $imp, $($args)*)
891 }};
892 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
893 {
894 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"]
895 macro_rules! debug(
896 () => {}
897 );
898 debug!();
899 }
900 $crate::log_with_level!($cat, $crate::DebugLevel::Debug, id = $id, $($args)*)
901 }};
902 ($cat:expr, $($args:tt)*) => { {
903 $crate::log_with_level!($cat, $crate::DebugLevel::Debug, $($args)*)
904 }};
905);
906
907#[macro_export]
908macro_rules! log(
909 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
910 $crate::log_with_level!($cat, $crate::DebugLevel::Log, obj = $obj, $($args)*)
911 }};
912 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
913 $crate::log_with_level!($cat, $crate::DebugLevel::Log, imp = $imp, $($args)*)
914 }};
915 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
916 $crate::log_with_level!($cat, $crate::DebugLevel::Log, id = $id, $($args)*)
917 }};
918
919 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
920 {
921 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
922 macro_rules! log(
923 () => {}
924 );
925 log!();
926 }
927 $crate::log_with_level!($cat, $crate::DebugLevel::Log, obj = $obj, $($args)*)
928 }};
929 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
930 {
931 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
932 macro_rules! log(
933 () => {}
934 );
935 log!();
936 }
937 $crate::log_with_level!($cat, $crate::DebugLevel::Log, imp = $imp, $($args)*)
938 }};
939 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
940 {
941 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"]
942 macro_rules! log(
943 () => {}
944 );
945 log!();
946 }
947 $crate::log_with_level!($cat, $crate::DebugLevel::Log, id = $id, $($args)*)
948 }};
949 ($cat:expr, $($args:tt)*) => { {
950 $crate::log_with_level!($cat, $crate::DebugLevel::Log, $($args)*)
951 }};
952);
953
954#[macro_export]
955macro_rules! trace(
956 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
957 $crate::log_with_level!($cat, $crate::DebugLevel::Trace, obj = $obj, $($args)*)
958 }};
959 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
960 $crate::log_with_level!($cat, $crate::DebugLevel::Trace, imp = $imp, $($args)*)
961 }};
962 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
963 $crate::log_with_level!($cat, $crate::DebugLevel::Trace, id = $id, $($args)*)
964 }};
965
966 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
967 {
968 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
969 macro_rules! trace(
970 () => {}
971 );
972 trace!();
973 }
974 $crate::log_with_level!($cat, $crate::DebugLevel::Trace, obj = $obj, $($args)*)
975 }};
976 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
977 {
978 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
979 macro_rules! trace(
980 () => {}
981 );
982 trace!();
983 }
984 $crate::log_with_level!($cat, $crate::DebugLevel::Trace, imp = $imp, $($args)*)
985 }};
986 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
987 {
988 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: `"]
989 macro_rules! trace(
990 () => {}
991 );
992 trace!();
993 }
994 $crate::log_with_level!($cat, $crate::DebugLevel::Trace, id = $id, $($args)*)
995 }};
996 ($cat:expr, $($args:tt)*) => { {
997 $crate::log_with_level!($cat, $crate::DebugLevel::Trace, $($args)*)
998 }};
999);
1000
1001#[macro_export]
1002macro_rules! memdump(
1003 ($cat:expr, obj = $obj:expr, $($args:tt)*) => { {
1004 $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, obj = $obj, $($args)*)
1005 }};
1006 ($cat:expr, imp = $imp:expr, $($args:tt)*) => { {
1007 $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, imp = $imp, $($args)*)
1008 }};
1009 ($cat:expr, id = $id:expr, $($args:tt)*) => { {
1010 $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, id = $id, $($args)*)
1011 }};
1012
1013 ($cat:expr, obj: $obj:expr, $($args:tt)*) => { {
1014 {
1015 #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"]
1016 macro_rules! memdump(
1017 () => {}
1018 );
1019 memdump!();
1020 }
1021 $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, obj = $obj, $($args)*)
1022 }};
1023 ($cat:expr, imp: $imp:expr, $($args:tt)*) => { {
1024 {
1025 #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"]
1026 macro_rules! memdump(
1027 () => {}
1028 );
1029 memdump!();
1030 }
1031 $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, imp = $imp, $($args)*)
1032 }};
1033 ($cat:expr, id: $id:expr, $($args:tt)*) => { {
1034 {
1035 #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"]
1036 macro_rules! memdump(
1037 () => {}
1038 );
1039 memdump!();
1040 }
1041 $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, id = $id, $($args)*)
1042 }};
1043 ($cat:expr, $($args:tt)*) => { {
1044 $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, $($args)*)
1045 }};
1046);
1047
1048#[macro_export]
1049macro_rules! log_with_level(
1050 ($cat:expr, $level:expr, obj = $obj:expr, $msg:literal) => { {
1051 let cat = $cat.clone();
1052
1053 #[allow(unused_unsafe)]
1056 #[allow(clippy::redundant_closure_call)]
1057 if cat.above_threshold($level) {
1058 use $crate::glib::prelude::Cast;
1059
1060 let obj = &$obj;
1064 let obj = unsafe { obj.unsafe_cast_ref::<$crate::glib::Object>() };
1065 let function_name = $crate::glib::function_name!();
1066
1067 (|args: std::fmt::Arguments| {
1071 if args.as_str().is_some() {
1072 $crate::DebugCategory::log_literal_unfiltered(
1073 cat,
1074 Some(obj),
1075 $level,
1076 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1077 function_name,
1078 line!(),
1079 $crate::glib::gstr!($msg),
1080 )
1081 } else {
1082 $crate::DebugCategory::log_unfiltered(
1083 cat,
1084 Some(obj),
1085 $level,
1086 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1087 function_name,
1088 line!(),
1089 args,
1090 )
1091 }
1092 })(format_args!($msg))
1093 }
1094 }};
1095 ($cat:expr, $level:expr, obj = $obj:expr, $($args:tt)*) => { {
1096 let cat = $cat.clone();
1097
1098 #[allow(unused_unsafe)]
1101 if cat.above_threshold($level) {
1102 use $crate::glib::prelude::Cast;
1103
1104 let obj = &$obj;
1108 let obj = unsafe { obj.unsafe_cast_ref::<$crate::glib::Object>() };
1109 $crate::DebugCategory::log_unfiltered(
1110 cat,
1111 Some(obj),
1112 $level,
1113 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1114 $crate::glib::function_name!(),
1115 line!(),
1116 format_args!($($args)*),
1117 )
1118 }
1119 }};
1120 ($cat:expr, $level:expr, imp = $imp:expr, $msg:literal) => { {
1121 let cat = $cat.clone();
1122
1123 #[allow(unused_unsafe)]
1126 #[allow(clippy::redundant_closure_call)]
1127 if cat.above_threshold($level) {
1128 use $crate::glib::prelude::Cast;
1129
1130 let obj = $imp.obj();
1134 let obj = unsafe { obj.unsafe_cast_ref::<$crate::glib::Object>() };
1135 let function_name = $crate::glib::function_name!();
1136
1137 (|args: std::fmt::Arguments| {
1141 if args.as_str().is_some() {
1142 $crate::DebugCategory::log_literal_unfiltered(
1143 cat,
1144 Some(obj),
1145 $level,
1146 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1147 function_name,
1148 line!(),
1149 $crate::glib::gstr!($msg),
1150 )
1151 } else {
1152 $crate::DebugCategory::log_unfiltered(
1153 cat,
1154 Some(obj),
1155 $level,
1156 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1157 function_name,
1158 line!(),
1159 args,
1160 )
1161 }
1162 })(format_args!($msg))
1163 }
1164 }};
1165 ($cat:expr, $level:expr, imp = $imp:expr, $($args:tt)*) => { {
1166 let cat = $cat.clone();
1167
1168 #[allow(unused_unsafe)]
1171 if cat.above_threshold($level) {
1172 use $crate::glib::prelude::Cast;
1173
1174 let obj = $imp.obj();
1178 let obj = unsafe { obj.unsafe_cast_ref::<$crate::glib::Object>() };
1179 $crate::DebugCategory::log_unfiltered(
1180 cat,
1181 Some(obj),
1182 $level,
1183 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1184 $crate::glib::function_name!(),
1185 line!(),
1186 format_args!($($args)*),
1187 )
1188 }
1189 }};
1190 ($cat:expr, $level:expr, id = $id:literal, $msg:literal) => { {
1191 let cat = $cat.clone();
1192
1193 #[allow(unused_unsafe)]
1196 #[allow(clippy::redundant_closure_call)]
1197 if cat.above_threshold($level) {
1198 let function_name = $crate::glib::function_name!();
1202
1203 (|args: std::fmt::Arguments| {
1207 if args.as_str().is_some() {
1208 $crate::DebugCategory::log_id_literal_unfiltered(
1209 cat,
1210 $crate::glib::gstr!($id),
1211 $level,
1212 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1213 function_name,
1214 line!(),
1215 $crate::glib::gstr!($msg),
1216 )
1217 } else {
1218 $crate::DebugCategory::log_id_unfiltered(
1219 cat,
1220 $crate::glib::gstr!($id),
1221 $level,
1222 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1223 function_name,
1224 line!(),
1225 args,
1226 )
1227 }
1228 })(format_args!($msg))
1229 }
1230 }};
1231 ($cat:expr, $level:expr, id = $id:literal, $($args:tt)*) => { {
1232 let cat = $cat.clone();
1233
1234 #[allow(unused_unsafe)]
1237 if cat.above_threshold($level) {
1238 $crate::DebugCategory::log_id_unfiltered(
1242 cat,
1243 $crate::glib::gstr!($id),
1244 $level,
1245 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1246 $crate::glib::function_name!(),
1247 line!(),
1248 format_args!($($args)*),
1249 )
1250 }
1251 }};
1252 ($cat:expr, $level:expr, id = $id:expr, $msg:literal) => { {
1253 let cat = $cat.clone();
1254
1255 #[allow(unused_unsafe)]
1258 #[allow(clippy::redundant_closure_call)]
1259 if cat.above_threshold($level) {
1260 let function_name = $crate::glib::function_name!();
1264
1265 (|args: std::fmt::Arguments| {
1269 if args.as_str().is_some() {
1270 $crate::DebugCategory::log_id_literal_unfiltered(
1271 cat,
1272 $id,
1273 $level,
1274 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1275 function_name,
1276 line!(),
1277 $crate::glib::gstr!($msg),
1278 )
1279 } else {
1280 $crate::DebugCategory::log_id_unfiltered(
1281 cat,
1282 $id,
1283 $level,
1284 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1285 function_name,
1286 line!(),
1287 args,
1288 )
1289 }
1290 })(format_args!($msg))
1291 }
1292 }};
1293 ($cat:expr, $level:expr, id = $id:expr, $($args:tt)*) => { {
1294 let cat = $cat.clone();
1295
1296 #[allow(unused_unsafe)]
1299 if cat.above_threshold($level) {
1300 $crate::DebugCategory::log_id_unfiltered(
1304 cat,
1305 $id,
1306 $level,
1307 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1308 $crate::glib::function_name!(),
1309 line!(),
1310 format_args!($($args)*),
1311 )
1312 }
1313 }};
1314 ($cat:expr, $level:expr, $msg:literal) => { {
1315 let cat = $cat.clone();
1316
1317 #[allow(unused_unsafe)]
1320 #[allow(clippy::redundant_closure_call)]
1321 if cat.above_threshold($level) {
1322 let function_name = $crate::glib::function_name!();
1326
1327 (|args: std::fmt::Arguments| {
1331 if args.as_str().is_some() {
1332 $crate::DebugCategory::log_literal_unfiltered(
1333 cat,
1334 None as Option<&$crate::glib::Object>,
1335 $level,
1336 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1337 function_name,
1338 line!(),
1339 $crate::glib::gstr!($msg),
1340 )
1341 } else {
1342 $crate::DebugCategory::log_unfiltered(
1343 cat,
1344 None as Option<&$crate::glib::Object>,
1345 $level,
1346 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1347 function_name,
1348 line!(),
1349 args,
1350 )
1351 }
1352 })(format_args!($msg))
1353 }
1354 }};
1355 ($cat:expr, $level:expr, $($args:tt)*) => { {
1356 let cat = $cat.clone();
1357
1358 #[allow(unused_unsafe)]
1361 if cat.above_threshold($level) {
1362 $crate::DebugCategory::log_unfiltered(
1366 cat,
1367 None as Option<&$crate::glib::Object>,
1368 $level,
1369 unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) },
1370 $crate::glib::function_name!(),
1371 line!(),
1372 format_args!($($args)*),
1373 )
1374 }
1375 }};
1376);
1377
1378#[cfg(feature = "log")]
1379#[cfg_attr(docsrs, doc(cfg(feature = "log")))]
1380#[derive(Debug)]
1381pub struct DebugCategoryLogger(DebugCategory);
1382
1383#[cfg(feature = "log")]
1384#[cfg_attr(docsrs, doc(cfg(feature = "log")))]
1385impl DebugCategoryLogger {
1386 pub fn new(cat: DebugCategory) -> Self {
1387 skip_assert_initialized!();
1388 Self(cat)
1389 }
1390
1391 fn to_level(level: log::Level) -> crate::DebugLevel {
1392 skip_assert_initialized!();
1393 match level {
1394 log::Level::Error => DebugLevel::Error,
1395 log::Level::Warn => DebugLevel::Warning,
1396 log::Level::Info => DebugLevel::Info,
1397 log::Level::Debug => DebugLevel::Debug,
1398 log::Level::Trace => DebugLevel::Trace,
1399 }
1400 }
1401}
1402
1403#[cfg(feature = "log")]
1404#[cfg_attr(docsrs, doc(cfg(feature = "log")))]
1405impl log::Log for DebugCategoryLogger {
1406 fn enabled(&self, metadata: &log::Metadata) -> bool {
1407 self.0.above_threshold(Self::to_level(metadata.level()))
1408 }
1409
1410 fn log(&self, record: &log::Record) {
1411 if !self.enabled(record.metadata()) {
1412 return;
1413 }
1414 record.file().unwrap_or("").run_with_gstr(|file| {
1415 self.0.log(
1416 None::<&glib::Object>,
1417 Self::to_level(record.level()),
1418 file,
1419 record.module_path().unwrap_or(""),
1420 record.line().unwrap_or(0),
1421 *record.args(),
1422 );
1423 });
1424 }
1425
1426 fn flush(&self) {}
1427}
1428
1429unsafe extern "C" fn log_handler<T>(
1430 category: *mut ffi::GstDebugCategory,
1431 level: ffi::GstDebugLevel,
1432 file: *const c_char,
1433 function: *const c_char,
1434 line: i32,
1435 object: *mut glib::gobject_ffi::GObject,
1436 message: *mut ffi::GstDebugMessage,
1437 user_data: gpointer,
1438) where
1439 T: Fn(
1440 DebugCategory,
1441 DebugLevel,
1442 &glib::GStr,
1443 &glib::GStr,
1444 u32,
1445 Option<&LoggedObject>,
1446 &DebugMessage,
1447 ) + Send
1448 + Sync
1449 + 'static,
1450{
1451 if category.is_null() {
1452 return;
1453 }
1454 let category = DebugCategory(Some(ptr::NonNull::new_unchecked(category)));
1455 let level = from_glib(level);
1456 let file = glib::GStr::from_ptr(file);
1457 let function = glib::GStr::from_ptr(function);
1458 let line = line as u32;
1459 let object = ptr::NonNull::new(object).map(LoggedObject);
1460 let message = DebugMessage(ptr::NonNull::new_unchecked(message));
1461 let handler = &*(user_data as *mut T);
1462 (handler)(
1463 category,
1464 level,
1465 file,
1466 function,
1467 line,
1468 object.as_ref(),
1469 &message,
1470 );
1471}
1472
1473unsafe extern "C" fn log_handler_data_free<T>(data: gpointer) {
1474 let data = Box::from_raw(data as *mut T);
1475 drop(data);
1476}
1477
1478#[derive(Debug)]
1479pub struct DebugLogFunction(ptr::NonNull<std::os::raw::c_void>);
1480
1481unsafe impl Send for DebugLogFunction {}
1485unsafe impl Sync for DebugLogFunction {}
1486
1487#[derive(Debug)]
1488#[doc(alias = "GObject")]
1489pub struct LoggedObject(ptr::NonNull<glib::gobject_ffi::GObject>);
1490
1491impl LoggedObject {
1492 #[inline]
1493 pub fn as_ptr(&self) -> *mut glib::gobject_ffi::GObject {
1494 self.0.as_ptr()
1495 }
1496}
1497
1498impl fmt::Display for LoggedObject {
1499 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1500 unsafe {
1501 let ptr = self.0.as_ptr();
1502 let g_type_instance = &mut (*ptr).g_type_instance;
1503 if glib::gobject_ffi::g_type_check_instance_is_fundamentally_a(
1504 g_type_instance,
1505 glib::gobject_ffi::g_object_get_type(),
1506 ) != glib::ffi::GFALSE
1507 {
1508 let type_ = (*g_type_instance.g_class).g_type;
1509
1510 if glib::gobject_ffi::g_type_is_a(type_, ffi::gst_pad_get_type())
1511 != glib::ffi::GFALSE
1512 {
1513 let name_ptr = (*(ptr as *mut ffi::GstObject)).name;
1514 let name = if name_ptr.is_null() {
1515 "<null>"
1516 } else {
1517 CStr::from_ptr(name_ptr)
1518 .to_str()
1519 .unwrap_or("<invalid name>")
1520 };
1521
1522 let parent_ptr = (*(ptr as *mut ffi::GstObject)).parent;
1523 let parent_name = if parent_ptr.is_null() {
1524 "<null>"
1525 } else {
1526 let name_ptr = (*(parent_ptr)).name;
1527 if name_ptr.is_null() {
1528 "<null>"
1529 } else {
1530 CStr::from_ptr(name_ptr)
1531 .to_str()
1532 .unwrap_or("<invalid name>")
1533 }
1534 };
1535
1536 write!(f, "{parent_name}:{name}")
1537 } else if glib::gobject_ffi::g_type_is_a(type_, ffi::gst_object_get_type())
1538 != glib::ffi::GFALSE
1539 {
1540 let name_ptr = (*(ptr as *mut ffi::GstObject)).name;
1541 let name = if name_ptr.is_null() {
1542 "<null>"
1543 } else {
1544 CStr::from_ptr(name_ptr)
1545 .to_str()
1546 .unwrap_or("<invalid name>")
1547 };
1548 write!(f, "{name}")
1549 } else {
1550 let type_name = CStr::from_ptr(glib::gobject_ffi::g_type_name(type_));
1551 write!(
1552 f,
1553 "{}:{:?}",
1554 type_name.to_str().unwrap_or("<invalid type>"),
1555 ptr
1556 )
1557 }
1558 } else {
1559 write!(f, "{ptr:?}")
1560 }
1561 }
1562 }
1563}
1564
1565#[doc(alias = "gst_debug_add_log_function")]
1566pub fn add_log_function<T>(function: T) -> DebugLogFunction
1567where
1568 T: Fn(
1569 DebugCategory,
1570 DebugLevel,
1571 &glib::GStr,
1572 &glib::GStr,
1573 u32,
1574 Option<&LoggedObject>,
1575 &DebugMessage,
1576 ) + Send
1577 + Sync
1578 + 'static,
1579{
1580 skip_assert_initialized!();
1581 unsafe {
1582 let user_data = Box::new(function);
1583 let user_data_ptr = Box::into_raw(user_data) as gpointer;
1584 ffi::gst_debug_add_log_function(
1585 Some(log_handler::<T>),
1586 user_data_ptr,
1587 Some(log_handler_data_free::<T>),
1588 );
1589 DebugLogFunction(ptr::NonNull::new_unchecked(user_data_ptr))
1590 }
1591}
1592
1593pub fn remove_default_log_function() {
1594 skip_assert_initialized!();
1595 unsafe {
1596 ffi::gst_debug_remove_log_function(None);
1597 }
1598}
1599
1600#[doc(alias = "gst_debug_remove_log_function_by_data")]
1601pub fn remove_log_function(log_fn: DebugLogFunction) {
1602 skip_assert_initialized!();
1603 unsafe {
1604 ffi::gst_debug_remove_log_function_by_data(log_fn.0.as_ptr());
1605 }
1606}
1607
1608#[cfg(test)]
1609mod tests {
1610 use std::sync::{mpsc, Arc, Mutex};
1611
1612 use super::*;
1613
1614 #[test]
1615 #[doc(alias = "get_existing")]
1616 fn existing() {
1617 crate::init().unwrap();
1618
1619 let perf_cat = DebugCategory::get("GST_PERFORMANCE")
1620 .expect("Unable to find `DebugCategory` with name \"GST_PERFORMANCE\"");
1621 assert_eq!(perf_cat.name(), CAT_PERFORMANCE.name());
1622 }
1623
1624 #[test]
1625 fn all() {
1626 crate::init().unwrap();
1627
1628 assert!(DebugCategory::all_categories()
1629 .iter()
1630 .any(|c| c.name() == "GST_PERFORMANCE"));
1631 }
1632
1633 #[test]
1634 fn new_and_log() {
1635 crate::init().unwrap();
1636
1637 let cat = DebugCategory::new(
1638 "test-cat",
1639 crate::DebugColorFlags::empty(),
1640 Some("some debug category"),
1641 );
1642
1643 error!(cat, "meh");
1644 warning!(cat, "meh");
1645 fixme!(cat, "meh");
1646 info!(cat, "meh");
1647 debug!(cat, "meh");
1648 log!(cat, "meh");
1649 trace!(cat, "meh");
1650 memdump!(cat, "meh");
1651
1652 let obj = crate::Bin::with_name("meh");
1653
1654 error!(cat, obj = &obj, "meh");
1655 warning!(cat, obj = &obj, "meh");
1656 fixme!(cat, obj = &obj, "meh");
1657 info!(cat, obj = &obj, "meh");
1658 debug!(cat, obj = &obj, "meh");
1659 log!(cat, obj = &obj, "meh");
1660 trace!(cat, obj = &obj, "meh");
1661 memdump!(cat, obj = &obj, "meh");
1662
1663 error!(cat, obj = obj, "meh");
1664 warning!(cat, obj = obj, "meh");
1665 fixme!(cat, obj = obj, "meh");
1666 info!(cat, obj = obj, "meh");
1667 debug!(cat, obj = obj, "meh");
1668 log!(cat, obj = obj, "meh");
1669 trace!(cat, obj = obj, "meh");
1670 memdump!(cat, obj = obj, "meh");
1671 }
1672
1673 #[cfg(feature = "log")]
1674 static LOGGER: Lazy<DebugCategoryLogger> = Lazy::new(|| {
1675 DebugCategoryLogger::new(DebugCategory::new(
1676 "Log_trait",
1677 crate::DebugColorFlags::empty(),
1678 Some("Using the Log trait"),
1679 ))
1680 });
1681
1682 #[test]
1683 #[cfg(feature = "log")]
1684 fn log_trait() {
1685 crate::init().unwrap();
1686
1687 log::set_logger(&(*LOGGER)).expect("Failed to set logger");
1688 log::set_max_level(log::LevelFilter::Trace);
1689 log::error!("meh");
1690 log::warn!("fish");
1691
1692 let (sender, receiver) = mpsc::channel();
1693 let sender = Arc::new(Mutex::new(sender));
1694 let handler = move |category: DebugCategory,
1695 level: DebugLevel,
1696 _file: &glib::GStr,
1697 _function: &glib::GStr,
1698 _line: u32,
1699 _object: Option<&LoggedObject>,
1700 message: &DebugMessage| {
1701 let cat = DebugCategory::get("Log_trait").unwrap();
1702
1703 if category != cat {
1704 return;
1707 }
1708
1709 assert_eq!(level, DebugLevel::Error);
1710 assert_eq!(message.get().unwrap().as_ref(), "meh");
1711 let _ = sender.lock().unwrap().send(());
1712 };
1713
1714 remove_default_log_function();
1715 add_log_function(handler);
1716
1717 let cat = LOGGER.0;
1718
1719 cat.set_threshold(crate::DebugLevel::Warning);
1720 log::error!("meh");
1721 receiver.recv().unwrap();
1722
1723 cat.set_threshold(crate::DebugLevel::Error);
1724 log::error!("meh");
1725 receiver.recv().unwrap();
1726
1727 cat.set_threshold(crate::DebugLevel::None);
1728 log::error!("fish");
1729 log::warn!("meh");
1730 }
1731
1732 #[test]
1733 fn log_handler() {
1734 crate::init().unwrap();
1735
1736 let cat = DebugCategory::new(
1737 "test-cat-log",
1738 crate::DebugColorFlags::empty(),
1739 Some("some debug category"),
1740 );
1741 cat.set_threshold(DebugLevel::Info);
1742 let obj = crate::Bin::with_name("meh");
1743
1744 let (sender, receiver) = mpsc::channel();
1745
1746 let sender = Arc::new(Mutex::new(sender));
1747
1748 let handler = move |category: DebugCategory,
1749 level: DebugLevel,
1750 _file: &glib::GStr,
1751 _function: &glib::GStr,
1752 _line: u32,
1753 _object: Option<&LoggedObject>,
1754 message: &DebugMessage| {
1755 let cat = DebugCategory::get("test-cat-log").unwrap();
1756
1757 if category != cat {
1758 return;
1761 }
1762
1763 assert_eq!(level, DebugLevel::Info);
1764 assert_eq!(message.get().unwrap().as_ref(), "meh");
1765 let _ = sender.lock().unwrap().send(());
1766 };
1767
1768 remove_default_log_function();
1769 let log_fn = add_log_function(handler);
1770 info!(cat, obj = &obj, "meh");
1771
1772 receiver.recv().unwrap();
1773
1774 remove_log_function(log_fn);
1775
1776 info!(cat, obj = &obj, "meh2");
1777 assert!(receiver.recv().is_err());
1778 }
1779
1780 #[test]
1781 fn no_argument_evaluation() {
1782 crate::init().unwrap();
1783
1784 let cat = DebugCategory::new(
1785 "no_argument_evaluation",
1786 crate::DebugColorFlags::empty(),
1787 Some("No Argument Evaluation debug category"),
1788 );
1789
1790 let mut arg_evaluated = false;
1791 trace!(cat, "{}", {
1792 arg_evaluated = true;
1793 "trace log"
1794 });
1795
1796 assert!(!arg_evaluated);
1797 }
1798
1799 #[cfg(feature = "v1_22")]
1800 #[test]
1801 fn id_logging() {
1802 crate::init().unwrap();
1803
1804 let cat = DebugCategory::new(
1805 "log_with_id_test_category",
1806 crate::DebugColorFlags::empty(),
1807 Some("Blablabla"),
1808 );
1809
1810 cat.set_threshold(crate::DebugLevel::Trace);
1811
1812 trace!(cat, id = "123", "test");
1813 trace!(cat, id = glib::GString::from("123"), "test");
1814 trace!(cat, id = &glib::GString::from("123"), "test");
1815
1816 let log_id = glib::GString::from("456");
1818 trace!(cat, id = &log_id, "{log_id:?}");
1819 }
1820}