gstreamer/
pad.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{
4    mem,
5    num::NonZeroU64,
6    ops::ControlFlow,
7    panic::{self, AssertUnwindSafe},
8    ptr,
9};
10
11use glib::{ffi::gpointer, prelude::*, translate::*};
12
13use crate::{
14    ffi,
15    format::{FormattedValue, SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic},
16    prelude::*,
17    Buffer, BufferList, Event, FlowError, FlowReturn, FlowSuccess, Format, GenericFormattedValue,
18    LoggableError, Pad, PadFlags, PadProbeReturn, PadProbeType, Query, QueryRef, StaticPadTemplate,
19};
20
21#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
22pub struct PadProbeId(NonZeroU64);
23
24impl IntoGlib for PadProbeId {
25    type GlibType = libc::c_ulong;
26
27    #[inline]
28    fn into_glib(self) -> libc::c_ulong {
29        self.0.get() as libc::c_ulong
30    }
31}
32
33impl FromGlib<libc::c_ulong> for PadProbeId {
34    #[inline]
35    unsafe fn from_glib(val: libc::c_ulong) -> PadProbeId {
36        skip_assert_initialized!();
37        debug_assert_ne!(val, 0);
38        PadProbeId(NonZeroU64::new_unchecked(val as _))
39    }
40}
41
42impl PadProbeId {
43    #[inline]
44    pub fn as_raw(&self) -> libc::c_ulong {
45        self.0.get() as libc::c_ulong
46    }
47}
48
49#[doc(alias = "GstPadProbeInfo")]
50#[derive(Debug)]
51pub struct PadProbeInfo<'a> {
52    pub mask: PadProbeType,
53    pub id: Option<PadProbeId>,
54    pub offset: u64,
55    pub size: u32,
56    pub data: Option<PadProbeData<'a>>,
57    pub flow_res: Result<FlowSuccess, FlowError>,
58}
59
60impl PadProbeInfo<'_> {
61    pub fn buffer(&self) -> Option<&Buffer> {
62        match self.data {
63            Some(PadProbeData::Buffer(ref buffer)) => Some(buffer),
64            _ => None,
65        }
66    }
67
68    pub fn buffer_mut(&mut self) -> Option<&mut Buffer> {
69        match self.data {
70            Some(PadProbeData::Buffer(ref mut buffer)) => Some(buffer),
71            _ => None,
72        }
73    }
74
75    pub fn buffer_list(&self) -> Option<&BufferList> {
76        match self.data {
77            Some(PadProbeData::BufferList(ref buffer_list)) => Some(buffer_list),
78            _ => None,
79        }
80    }
81
82    pub fn buffer_list_mut(&mut self) -> Option<&mut BufferList> {
83        match self.data {
84            Some(PadProbeData::BufferList(ref mut buffer_list)) => Some(buffer_list),
85            _ => None,
86        }
87    }
88
89    pub fn query(&self) -> Option<&QueryRef> {
90        match self.data {
91            Some(PadProbeData::Query(ref query)) => Some(*query),
92            _ => None,
93        }
94    }
95
96    pub fn query_mut(&mut self) -> Option<&mut QueryRef> {
97        match self.data {
98            Some(PadProbeData::Query(ref mut query)) => Some(*query),
99            _ => None,
100        }
101    }
102
103    pub fn event(&self) -> Option<&Event> {
104        match self.data {
105            Some(PadProbeData::Event(ref event)) => Some(event),
106            _ => None,
107        }
108    }
109
110    pub fn event_mut(&mut self) -> Option<&mut Event> {
111        match self.data {
112            Some(PadProbeData::Event(ref mut event)) => Some(event),
113            _ => None,
114        }
115    }
116
117    // rustdoc-stripper-ignore-next
118    /// Takes over the buffer in the probe info. As the data is no longer valid for the caller, the
119    /// probe will be considered dropped after this point.
120    pub fn take_buffer(&mut self) -> Option<Buffer> {
121        if matches!(self.data, Some(PadProbeData::Buffer(..))) {
122            match self.data.take() {
123                Some(PadProbeData::Buffer(b)) => Some(b),
124                _ => unreachable!(),
125            }
126        } else {
127            None
128        }
129    }
130
131    // rustdoc-stripper-ignore-next
132    /// Takes over the buffer in the probe info. As the data is no longer valid for the caller, the
133    /// probe will be considered dropped after this point.
134    pub fn take_buffer_list(&mut self) -> Option<BufferList> {
135        if matches!(self.data, Some(PadProbeData::BufferList(..))) {
136            match self.data.take() {
137                Some(PadProbeData::BufferList(b)) => Some(b),
138                _ => unreachable!(),
139            }
140        } else {
141            None
142        }
143    }
144    // rustdoc-stripper-ignore-next
145    /// Takes over the event in the probe info. As the data is no longer valid for the caller, the
146    /// probe will be considered dropped after this point.
147    pub fn take_event(&mut self) -> Option<Event> {
148        if matches!(self.data, Some(PadProbeData::Event(..))) {
149            match self.data.take() {
150                Some(PadProbeData::Event(e)) => Some(e),
151                _ => unreachable!(),
152            }
153        } else {
154            None
155        }
156    }
157}
158
159#[derive(Debug)]
160pub enum PadProbeData<'a> {
161    Buffer(Buffer),
162    BufferList(BufferList),
163    Query(&'a mut QueryRef),
164    Event(Event),
165    #[doc(hidden)]
166    __Unknown(*mut ffi::GstMiniObject),
167}
168
169unsafe impl Send for PadProbeData<'_> {}
170unsafe impl Sync for PadProbeData<'_> {}
171
172#[derive(Debug)]
173#[must_use = "if unused the StreamLock will immediately unlock"]
174pub struct StreamLock<'a>(&'a Pad);
175impl Drop for StreamLock<'_> {
176    #[inline]
177    fn drop(&mut self) {
178        unsafe {
179            let pad: *mut ffi::GstPad = self.0.to_glib_none().0;
180            glib::ffi::g_rec_mutex_unlock(&mut (*pad).stream_rec_lock);
181        }
182    }
183}
184
185#[derive(Debug)]
186pub enum PadGetRangeSuccess {
187    FilledBuffer,
188    NewBuffer(crate::Buffer),
189}
190
191#[derive(Debug)]
192pub enum EventForeachAction {
193    Keep,
194    Remove,
195    Replace(Event),
196}
197
198mod sealed {
199    pub trait Sealed {}
200    impl<T: super::IsA<super::Pad>> Sealed for T {}
201}
202
203pub trait PadExtManual: sealed::Sealed + IsA<Pad> + 'static {
204    #[doc(alias = "gst_pad_add_probe")]
205    fn add_probe<F>(&self, mask: PadProbeType, func: F) -> Option<PadProbeId>
206    where
207        F: Fn(&Self, &mut PadProbeInfo) -> PadProbeReturn + Send + Sync + 'static,
208    {
209        unsafe {
210            let func_box: Box<F> = Box::new(func);
211            let id = ffi::gst_pad_add_probe(
212                self.as_ref().to_glib_none().0,
213                mask.into_glib(),
214                Some(trampoline_pad_probe::<Self, F>),
215                Box::into_raw(func_box) as gpointer,
216                Some(destroy_closure::<F>),
217            );
218
219            if id == 0 {
220                None
221            } else {
222                Some(from_glib(id))
223            }
224        }
225    }
226
227    #[doc(alias = "gst_pad_remove_probe")]
228    fn remove_probe(&self, id: PadProbeId) {
229        unsafe {
230            ffi::gst_pad_remove_probe(self.as_ref().to_glib_none().0, id.into_glib());
231        }
232    }
233
234    #[doc(alias = "gst_pad_pull_range")]
235    fn pull_range(&self, offset: u64, size: u32) -> Result<Buffer, FlowError> {
236        unsafe {
237            let mut buffer = ptr::null_mut();
238            FlowSuccess::try_from_glib(ffi::gst_pad_pull_range(
239                self.as_ref().to_glib_none().0,
240                offset,
241                size,
242                &mut buffer,
243            ))
244            .map(|_| from_glib_full(buffer))
245        }
246    }
247
248    fn pull_range_fill(
249        &self,
250        offset: u64,
251        buffer: &mut crate::BufferRef,
252        size: u32,
253    ) -> Result<(), FlowError> {
254        assert!(buffer.size() >= size as usize);
255
256        unsafe {
257            let mut buffer_ref = buffer.as_mut_ptr();
258            FlowSuccess::try_from_glib(ffi::gst_pad_pull_range(
259                self.as_ref().to_glib_none().0,
260                offset,
261                size,
262                &mut buffer_ref,
263            ))
264            .and_then(|_| {
265                if buffer.as_mut_ptr() != buffer_ref {
266                    ffi::gst_mini_object_unref(buffer_ref as *mut _);
267                    Err(crate::FlowError::Error)
268                } else {
269                    Ok(())
270                }
271            })
272        }
273    }
274
275    #[doc(alias = "get_range")]
276    #[doc(alias = "gst_pad_get_range")]
277    fn range(&self, offset: u64, size: u32) -> Result<Buffer, FlowError> {
278        unsafe {
279            let mut buffer = ptr::null_mut();
280            FlowSuccess::try_from_glib(ffi::gst_pad_get_range(
281                self.as_ref().to_glib_none().0,
282                offset,
283                size,
284                &mut buffer,
285            ))
286            .map(|_| from_glib_full(buffer))
287        }
288    }
289
290    #[doc(alias = "get_range_fill")]
291    fn range_fill(
292        &self,
293        offset: u64,
294        buffer: &mut crate::BufferRef,
295        size: u32,
296    ) -> Result<(), FlowError> {
297        assert!(buffer.size() >= size as usize);
298
299        unsafe {
300            let mut buffer_ref = buffer.as_mut_ptr();
301            FlowSuccess::try_from_glib(ffi::gst_pad_get_range(
302                self.as_ref().to_glib_none().0,
303                offset,
304                size,
305                &mut buffer_ref,
306            ))
307            .and_then(|_| {
308                if buffer.as_mut_ptr() != buffer_ref {
309                    ffi::gst_mini_object_unref(buffer_ref as *mut _);
310                    Err(crate::FlowError::Error)
311                } else {
312                    Ok(())
313                }
314            })
315        }
316    }
317
318    #[doc(alias = "gst_pad_peer_query")]
319    fn peer_query(&self, query: &mut QueryRef) -> bool {
320        unsafe {
321            from_glib(ffi::gst_pad_peer_query(
322                self.as_ref().to_glib_none().0,
323                query.as_mut_ptr(),
324            ))
325        }
326    }
327
328    #[doc(alias = "gst_pad_query")]
329    fn query(&self, query: &mut QueryRef) -> bool {
330        unsafe {
331            from_glib(ffi::gst_pad_query(
332                self.as_ref().to_glib_none().0,
333                query.as_mut_ptr(),
334            ))
335        }
336    }
337
338    #[doc(alias = "gst_pad_proxy_query_caps")]
339    fn proxy_query_caps(&self, query: &mut QueryRef) -> bool {
340        unsafe {
341            from_glib(ffi::gst_pad_proxy_query_caps(
342                self.as_ref().to_glib_none().0,
343                query.as_mut_ptr(),
344            ))
345        }
346    }
347
348    #[doc(alias = "gst_pad_proxy_query_accept_caps")]
349    fn proxy_query_accept_caps(&self, query: &mut QueryRef) -> bool {
350        unsafe {
351            from_glib(ffi::gst_pad_proxy_query_accept_caps(
352                self.as_ref().to_glib_none().0,
353                query.as_mut_ptr(),
354            ))
355        }
356    }
357
358    #[doc(alias = "gst_pad_push_event")]
359    fn push_event(&self, event: impl Into<Event>) -> bool {
360        unsafe {
361            from_glib(ffi::gst_pad_push_event(
362                self.as_ref().to_glib_none().0,
363                event.into().into_glib_ptr(),
364            ))
365        }
366    }
367
368    #[doc(alias = "gst_pad_send_event")]
369    fn send_event(&self, event: impl Into<Event>) -> bool {
370        unsafe {
371            from_glib(ffi::gst_pad_send_event(
372                self.as_ref().to_glib_none().0,
373                event.into().into_glib_ptr(),
374            ))
375        }
376    }
377
378    #[doc(alias = "gst_pad_iterate_internal_links")]
379    fn iterate_internal_links(&self) -> crate::Iterator<Pad> {
380        unsafe {
381            from_glib_full(ffi::gst_pad_iterate_internal_links(
382                self.as_ref().to_glib_none().0,
383            ))
384        }
385    }
386
387    fn stream_lock(&self) -> StreamLock {
388        unsafe {
389            let ptr: &mut ffi::GstPad = &mut *(self.as_ptr() as *mut _);
390            glib::ffi::g_rec_mutex_lock(&mut ptr.stream_rec_lock);
391            StreamLock(self.upcast_ref())
392        }
393    }
394
395    #[doc(alias = "gst_pad_set_activate_function")]
396    #[doc(alias = "gst_pad_set_activate_function_full")]
397    unsafe fn set_activate_function<F>(&self, func: F)
398    where
399        F: Fn(&Self, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static,
400    {
401        let func_box: Box<F> = Box::new(func);
402        ffi::gst_pad_set_activate_function_full(
403            self.as_ref().to_glib_none().0,
404            Some(trampoline_activate_function::<Self, F>),
405            Box::into_raw(func_box) as gpointer,
406            Some(destroy_closure::<F>),
407        );
408    }
409
410    #[doc(alias = "gst_pad_set_activatemode_function")]
411    #[doc(alias = "gst_pad_set_activatemode_function_full")]
412    unsafe fn set_activatemode_function<F>(&self, func: F)
413    where
414        F: Fn(&Self, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError>
415            + Send
416            + Sync
417            + 'static,
418    {
419        let func_box: Box<F> = Box::new(func);
420        ffi::gst_pad_set_activatemode_function_full(
421            self.as_ref().to_glib_none().0,
422            Some(trampoline_activatemode_function::<Self, F>),
423            Box::into_raw(func_box) as gpointer,
424            Some(destroy_closure::<F>),
425        );
426    }
427
428    #[doc(alias = "gst_pad_set_chain_function")]
429    #[doc(alias = "gst_pad_set_chain_function_full")]
430    unsafe fn set_chain_function<F>(&self, func: F)
431    where
432        F: Fn(&Self, Option<&crate::Object>, crate::Buffer) -> Result<FlowSuccess, FlowError>
433            + Send
434            + Sync
435            + 'static,
436    {
437        let func_box: Box<F> = Box::new(func);
438        ffi::gst_pad_set_chain_function_full(
439            self.as_ref().to_glib_none().0,
440            Some(trampoline_chain_function::<Self, F>),
441            Box::into_raw(func_box) as gpointer,
442            Some(destroy_closure::<F>),
443        );
444    }
445
446    #[doc(alias = "gst_pad_set_chain_list_function")]
447    #[doc(alias = "gst_pad_set_chain_list_function_full")]
448    unsafe fn set_chain_list_function<F>(&self, func: F)
449    where
450        F: Fn(&Self, Option<&crate::Object>, crate::BufferList) -> Result<FlowSuccess, FlowError>
451            + Send
452            + Sync
453            + 'static,
454    {
455        let func_box: Box<F> = Box::new(func);
456        ffi::gst_pad_set_chain_list_function_full(
457            self.as_ref().to_glib_none().0,
458            Some(trampoline_chain_list_function::<Self, F>),
459            Box::into_raw(func_box) as gpointer,
460            Some(destroy_closure::<F>),
461        );
462    }
463
464    #[doc(alias = "gst_pad_set_event_function")]
465    #[doc(alias = "gst_pad_set_event_function_full")]
466    unsafe fn set_event_function<F>(&self, func: F)
467    where
468        F: Fn(&Self, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static,
469    {
470        let func_box: Box<F> = Box::new(func);
471        ffi::gst_pad_set_event_function_full(
472            self.as_ref().to_glib_none().0,
473            Some(trampoline_event_function::<Self, F>),
474            Box::into_raw(func_box) as gpointer,
475            Some(destroy_closure::<F>),
476        );
477    }
478
479    #[doc(alias = "gst_pad_set_event_full_function")]
480    #[doc(alias = "gst_pad_set_event_full_function_full")]
481    unsafe fn set_event_full_function<F>(&self, func: F)
482    where
483        F: Fn(&Self, Option<&crate::Object>, crate::Event) -> Result<FlowSuccess, FlowError>
484            + Send
485            + Sync
486            + 'static,
487    {
488        let func_box: Box<F> = Box::new(func);
489        ffi::gst_pad_set_event_full_function_full(
490            self.as_ref().to_glib_none().0,
491            Some(trampoline_event_full_function::<Self, F>),
492            Box::into_raw(func_box) as gpointer,
493            Some(destroy_closure::<F>),
494        );
495    }
496
497    #[doc(alias = "gst_pad_set_getrange_function")]
498    #[doc(alias = "gst_pad_set_getrange_function_full")]
499    unsafe fn set_getrange_function<F>(&self, func: F)
500    where
501        F: Fn(
502                &Self,
503                Option<&crate::Object>,
504                u64,
505                Option<&mut crate::BufferRef>,
506                u32,
507            ) -> Result<PadGetRangeSuccess, crate::FlowError>
508            + Send
509            + Sync
510            + 'static,
511    {
512        let func_box: Box<F> = Box::new(func);
513        ffi::gst_pad_set_getrange_function_full(
514            self.as_ref().to_glib_none().0,
515            Some(trampoline_getrange_function::<Self, F>),
516            Box::into_raw(func_box) as gpointer,
517            Some(destroy_closure::<F>),
518        );
519    }
520
521    #[doc(alias = "gst_pad_set_iterate_internal_links_function")]
522    #[doc(alias = "gst_pad_set_iterate_internal_links_function_full")]
523    unsafe fn set_iterate_internal_links_function<F>(&self, func: F)
524    where
525        F: Fn(&Self, Option<&crate::Object>) -> crate::Iterator<Pad> + Send + Sync + 'static,
526    {
527        let func_box: Box<F> = Box::new(func);
528        ffi::gst_pad_set_iterate_internal_links_function_full(
529            self.as_ref().to_glib_none().0,
530            Some(trampoline_iterate_internal_links_function::<Self, F>),
531            Box::into_raw(func_box) as gpointer,
532            Some(destroy_closure::<F>),
533        );
534    }
535
536    #[doc(alias = "gst_pad_set_link_function")]
537    #[doc(alias = "gst_pad_set_link_function_full")]
538    unsafe fn set_link_function<F>(&self, func: F)
539    where
540        F: Fn(
541                &Self,
542                Option<&crate::Object>,
543                &Pad,
544            ) -> Result<crate::PadLinkSuccess, crate::PadLinkError>
545            + Send
546            + Sync
547            + 'static,
548    {
549        let func_box: Box<F> = Box::new(func);
550        ffi::gst_pad_set_link_function_full(
551            self.as_ref().to_glib_none().0,
552            Some(trampoline_link_function::<Self, F>),
553            Box::into_raw(func_box) as gpointer,
554            Some(destroy_closure::<F>),
555        );
556    }
557
558    #[doc(alias = "gst_pad_set_query_function")]
559    #[doc(alias = "gst_pad_set_query_function_full")]
560    unsafe fn set_query_function<F>(&self, func: F)
561    where
562        F: Fn(&Self, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static,
563    {
564        let func_box: Box<F> = Box::new(func);
565        ffi::gst_pad_set_query_function_full(
566            self.as_ref().to_glib_none().0,
567            Some(trampoline_query_function::<Self, F>),
568            Box::into_raw(func_box) as gpointer,
569            Some(destroy_closure::<F>),
570        );
571    }
572
573    #[doc(alias = "gst_pad_set_unlink_function")]
574    #[doc(alias = "gst_pad_set_unlink_function_full")]
575    unsafe fn set_unlink_function<F>(&self, func: F)
576    where
577        F: Fn(&Self, Option<&crate::Object>) + Send + Sync + 'static,
578    {
579        let func_box: Box<F> = Box::new(func);
580        ffi::gst_pad_set_unlink_function_full(
581            self.as_ref().to_glib_none().0,
582            Some(trampoline_unlink_function::<Self, F>),
583            Box::into_raw(func_box) as gpointer,
584            Some(destroy_closure::<F>),
585        );
586    }
587
588    #[doc(alias = "gst_pad_start_task")]
589    fn start_task<F: FnMut() + Send + 'static>(&self, func: F) -> Result<(), glib::BoolError> {
590        unsafe extern "C" fn trampoline_pad_task<F: FnMut() + Send + 'static>(func: gpointer) {
591            let (func, pad) = &mut *(func as *mut (F, *mut ffi::GstPad));
592            let pad = Pad::from_glib_borrow(*pad);
593            let result = panic::catch_unwind(AssertUnwindSafe(func));
594
595            if let Err(err) = result {
596                let element = match pad.parent_element() {
597                    Some(element) => element,
598                    None => panic::resume_unwind(err),
599                };
600
601                if pad.pause_task().is_err() {
602                    crate::error!(crate::CAT_RUST, "could not stop pad task on panic");
603                }
604
605                crate::subclass::post_panic_error_message(&element, pad.upcast_ref(), Some(err));
606            }
607        }
608
609        fn into_raw_pad_task<F: FnMut() + Send + 'static>(
610            func: F,
611            pad: *mut ffi::GstPad,
612        ) -> gpointer {
613            #[allow(clippy::type_complexity)]
614            let func: Box<(F, *mut ffi::GstPad)> = Box::new((func, pad));
615            Box::into_raw(func) as gpointer
616        }
617
618        unsafe extern "C" fn destroy_closure_pad_task<F>(ptr: gpointer) {
619            let _ = Box::<(F, *mut ffi::GstPad)>::from_raw(ptr as *mut _);
620        }
621
622        unsafe {
623            glib::result_from_gboolean!(
624                ffi::gst_pad_start_task(
625                    self.as_ref().to_glib_none().0,
626                    Some(trampoline_pad_task::<F>),
627                    into_raw_pad_task(func, self.upcast_ref().as_ptr()),
628                    Some(destroy_closure_pad_task::<F>),
629                ),
630                "Failed to start pad task",
631            )
632        }
633    }
634    #[doc(alias = "gst_pad_peer_query_convert")]
635    fn peer_query_convert<U: SpecificFormattedValueFullRange>(
636        &self,
637        src_val: impl FormattedValue,
638    ) -> Option<U> {
639        unsafe {
640            let mut dest_val = mem::MaybeUninit::uninit();
641            let ret = from_glib(ffi::gst_pad_peer_query_convert(
642                self.as_ref().to_glib_none().0,
643                src_val.format().into_glib(),
644                src_val.into_raw_value(),
645                U::default_format().into_glib(),
646                dest_val.as_mut_ptr(),
647            ));
648            if ret {
649                Some(U::from_raw(U::default_format(), dest_val.assume_init()))
650            } else {
651                None
652            }
653        }
654    }
655
656    #[doc(alias = "gst_pad_peer_query_convert")]
657    fn peer_query_convert_generic(
658        &self,
659        src_val: impl FormattedValue,
660        dest_format: Format,
661    ) -> Option<GenericFormattedValue> {
662        unsafe {
663            let mut dest_val = mem::MaybeUninit::uninit();
664            let ret = from_glib(ffi::gst_pad_peer_query_convert(
665                self.as_ref().to_glib_none().0,
666                src_val.format().into_glib(),
667                src_val.into_raw_value(),
668                dest_format.into_glib(),
669                dest_val.as_mut_ptr(),
670            ));
671            if ret {
672                Some(GenericFormattedValue::new(
673                    dest_format,
674                    dest_val.assume_init(),
675                ))
676            } else {
677                None
678            }
679        }
680    }
681
682    #[doc(alias = "gst_pad_peer_query_duration")]
683    fn peer_query_duration<T: SpecificFormattedValueIntrinsic>(&self) -> Option<T> {
684        unsafe {
685            let mut duration = mem::MaybeUninit::uninit();
686            let ret = from_glib(ffi::gst_pad_peer_query_duration(
687                self.as_ref().to_glib_none().0,
688                T::default_format().into_glib(),
689                duration.as_mut_ptr(),
690            ));
691            if ret {
692                try_from_glib(duration.assume_init()).ok()
693            } else {
694                None
695            }
696        }
697    }
698
699    #[doc(alias = "gst_pad_peer_query_duration")]
700    fn peer_query_duration_generic(&self, format: Format) -> Option<GenericFormattedValue> {
701        unsafe {
702            let mut duration = mem::MaybeUninit::uninit();
703            let ret = from_glib(ffi::gst_pad_peer_query_duration(
704                self.as_ref().to_glib_none().0,
705                format.into_glib(),
706                duration.as_mut_ptr(),
707            ));
708            if ret {
709                Some(GenericFormattedValue::new(format, duration.assume_init()))
710            } else {
711                None
712            }
713        }
714    }
715
716    #[doc(alias = "gst_pad_peer_query_position")]
717    fn peer_query_position<T: SpecificFormattedValueIntrinsic>(&self) -> Option<T> {
718        unsafe {
719            let mut cur = mem::MaybeUninit::uninit();
720            let ret = from_glib(ffi::gst_pad_peer_query_position(
721                self.as_ref().to_glib_none().0,
722                T::default_format().into_glib(),
723                cur.as_mut_ptr(),
724            ));
725            if ret {
726                try_from_glib(cur.assume_init()).ok()
727            } else {
728                None
729            }
730        }
731    }
732
733    #[doc(alias = "gst_pad_peer_query_position")]
734    fn peer_query_position_generic(&self, format: Format) -> Option<GenericFormattedValue> {
735        unsafe {
736            let mut cur = mem::MaybeUninit::uninit();
737            let ret = from_glib(ffi::gst_pad_peer_query_position(
738                self.as_ref().to_glib_none().0,
739                format.into_glib(),
740                cur.as_mut_ptr(),
741            ));
742            if ret {
743                Some(GenericFormattedValue::new(format, cur.assume_init()))
744            } else {
745                None
746            }
747        }
748    }
749
750    #[doc(alias = "gst_pad_query_convert")]
751    fn query_convert<U: SpecificFormattedValueFullRange>(
752        &self,
753        src_val: impl FormattedValue,
754    ) -> Option<U> {
755        unsafe {
756            let mut dest_val = mem::MaybeUninit::uninit();
757            let ret = from_glib(ffi::gst_pad_query_convert(
758                self.as_ref().to_glib_none().0,
759                src_val.format().into_glib(),
760                src_val.into_raw_value(),
761                U::default_format().into_glib(),
762                dest_val.as_mut_ptr(),
763            ));
764            if ret {
765                Some(U::from_raw(U::default_format(), dest_val.assume_init()))
766            } else {
767                None
768            }
769        }
770    }
771
772    #[doc(alias = "gst_pad_query_convert")]
773    fn query_convert_generic(
774        &self,
775        src_val: impl FormattedValue,
776        dest_format: Format,
777    ) -> Option<GenericFormattedValue> {
778        unsafe {
779            let mut dest_val = mem::MaybeUninit::uninit();
780            let ret = from_glib(ffi::gst_pad_query_convert(
781                self.as_ref().to_glib_none().0,
782                src_val.format().into_glib(),
783                src_val.into_raw_value(),
784                dest_format.into_glib(),
785                dest_val.as_mut_ptr(),
786            ));
787            if ret {
788                Some(GenericFormattedValue::new(
789                    dest_format,
790                    dest_val.assume_init(),
791                ))
792            } else {
793                None
794            }
795        }
796    }
797
798    #[doc(alias = "gst_pad_query_duration")]
799    fn query_duration<T: SpecificFormattedValueIntrinsic>(&self) -> Option<T> {
800        unsafe {
801            let mut duration = mem::MaybeUninit::uninit();
802            let ret = from_glib(ffi::gst_pad_query_duration(
803                self.as_ref().to_glib_none().0,
804                T::default_format().into_glib(),
805                duration.as_mut_ptr(),
806            ));
807            if ret {
808                try_from_glib(duration.assume_init()).ok()
809            } else {
810                None
811            }
812        }
813    }
814
815    #[doc(alias = "gst_pad_query_duration")]
816    fn query_duration_generic(&self, format: Format) -> Option<GenericFormattedValue> {
817        unsafe {
818            let mut duration = mem::MaybeUninit::uninit();
819            let ret = from_glib(ffi::gst_pad_query_duration(
820                self.as_ref().to_glib_none().0,
821                format.into_glib(),
822                duration.as_mut_ptr(),
823            ));
824            if ret {
825                Some(GenericFormattedValue::new(format, duration.assume_init()))
826            } else {
827                None
828            }
829        }
830    }
831
832    #[doc(alias = "gst_pad_query_position")]
833    fn query_position<T: SpecificFormattedValueIntrinsic>(&self) -> Option<T> {
834        unsafe {
835            let mut cur = mem::MaybeUninit::uninit();
836            let ret = from_glib(ffi::gst_pad_query_position(
837                self.as_ref().to_glib_none().0,
838                T::default_format().into_glib(),
839                cur.as_mut_ptr(),
840            ));
841            if ret {
842                try_from_glib(cur.assume_init()).ok()
843            } else {
844                None
845            }
846        }
847    }
848
849    #[doc(alias = "gst_pad_query_position")]
850    fn query_position_generic(&self, format: Format) -> Option<GenericFormattedValue> {
851        unsafe {
852            let mut cur = mem::MaybeUninit::uninit();
853            let ret = from_glib(ffi::gst_pad_query_position(
854                self.as_ref().to_glib_none().0,
855                format.into_glib(),
856                cur.as_mut_ptr(),
857            ));
858            if ret {
859                Some(GenericFormattedValue::new(format, cur.assume_init()))
860            } else {
861                None
862            }
863        }
864    }
865
866    #[doc(alias = "get_mode")]
867    #[doc(alias = "GST_PAD_MODE")]
868    fn mode(&self) -> crate::PadMode {
869        unsafe {
870            let ptr: &ffi::GstPad = &*(self.as_ptr() as *const _);
871            from_glib(ptr.mode)
872        }
873    }
874
875    #[doc(alias = "gst_pad_sticky_events_foreach")]
876    fn sticky_events_foreach<
877        F: FnMut(&Event) -> ControlFlow<EventForeachAction, EventForeachAction>,
878    >(
879        &self,
880        func: F,
881    ) {
882        unsafe extern "C" fn trampoline<
883            F: FnMut(&Event) -> ControlFlow<EventForeachAction, EventForeachAction>,
884        >(
885            _pad: *mut ffi::GstPad,
886            event: *mut *mut ffi::GstEvent,
887            user_data: glib::ffi::gpointer,
888        ) -> glib::ffi::gboolean {
889            let func = user_data as *mut F;
890            let res = (*func)(&from_glib_borrow(*event));
891
892            let (do_continue, ev_action) = match res {
893                ControlFlow::Continue(ev_action) => (glib::ffi::GTRUE, ev_action),
894                ControlFlow::Break(ev_action) => (glib::ffi::GFALSE, ev_action),
895            };
896
897            use EventForeachAction::*;
898
899            match ev_action {
900                Keep => (), // do nothing
901                Remove => {
902                    ffi::gst_mini_object_unref(*event as *mut _);
903                    *event = ptr::null_mut();
904                }
905                Replace(ev) => {
906                    ffi::gst_mini_object_unref(*event as *mut _);
907                    *event = ev.into_glib_ptr();
908                }
909            }
910
911            do_continue
912        }
913
914        unsafe {
915            let mut func = func;
916            let func_ptr = &mut func as *mut F as glib::ffi::gpointer;
917
918            ffi::gst_pad_sticky_events_foreach(
919                self.as_ref().to_glib_none().0,
920                Some(trampoline::<F>),
921                func_ptr,
922            );
923        }
924    }
925
926    #[doc(alias = "gst_pad_get_sticky_event")]
927    #[doc(alias = "get_sticky_event")]
928    fn sticky_event<T: crate::event::StickyEventType>(&self, idx: u32) -> Option<T::Owned> {
929        unsafe {
930            let ptr = ffi::gst_pad_get_sticky_event(
931                self.as_ref().to_glib_none().0,
932                T::TYPE.into_glib(),
933                idx,
934            );
935
936            if ptr.is_null() {
937                None
938            } else {
939                Some(T::from_event(from_glib_full(ptr)))
940            }
941        }
942    }
943
944    fn set_pad_flags(&self, flags: PadFlags) {
945        unsafe {
946            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
947            let _guard = self.as_ref().object_lock();
948            (*ptr).flags |= flags.into_glib();
949        }
950    }
951
952    fn unset_pad_flags(&self, flags: PadFlags) {
953        unsafe {
954            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
955            let _guard = self.as_ref().object_lock();
956            (*ptr).flags &= !flags.into_glib();
957        }
958    }
959
960    #[doc(alias = "get_pad_flags")]
961    fn pad_flags(&self) -> PadFlags {
962        unsafe {
963            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
964            let _guard = self.as_ref().object_lock();
965            from_glib((*ptr).flags)
966        }
967    }
968}
969
970impl<O: IsA<Pad>> PadExtManual for O {}
971
972unsafe fn create_probe_info<'a>(
973    info: *mut ffi::GstPadProbeInfo,
974) -> (PadProbeInfo<'a>, Option<glib::Type>) {
975    let mut data_type = None;
976    let flow_res = try_from_glib((*info).ABI.abi.flow_ret);
977    let info = PadProbeInfo {
978        mask: from_glib((*info).type_),
979        id: Some(PadProbeId(NonZeroU64::new_unchecked((*info).id as _))),
980        offset: (*info).offset,
981        size: (*info).size,
982        data: if (*info).data.is_null() {
983            None
984        } else {
985            let data = (*info).data as *mut ffi::GstMiniObject;
986            (*info).data = ptr::null_mut();
987            if (*data).type_ == Buffer::static_type().into_glib() {
988                data_type = Some(Buffer::static_type());
989                Some(PadProbeData::Buffer(from_glib_full(
990                    data as *const ffi::GstBuffer,
991                )))
992            } else if (*data).type_ == BufferList::static_type().into_glib() {
993                data_type = Some(BufferList::static_type());
994                Some(PadProbeData::BufferList(from_glib_full(
995                    data as *const ffi::GstBufferList,
996                )))
997            } else if (*data).type_ == Query::static_type().into_glib() {
998                data_type = Some(Query::static_type());
999                Some(PadProbeData::Query(QueryRef::from_mut_ptr(
1000                    data as *mut ffi::GstQuery,
1001                )))
1002            } else if (*data).type_ == Event::static_type().into_glib() {
1003                data_type = Some(Event::static_type());
1004                Some(PadProbeData::Event(from_glib_full(
1005                    data as *const ffi::GstEvent,
1006                )))
1007            } else {
1008                Some(PadProbeData::__Unknown(data))
1009            }
1010        },
1011        flow_res,
1012    };
1013    (info, data_type)
1014}
1015
1016unsafe fn update_probe_info(
1017    ret: PadProbeReturn,
1018    probe_info: PadProbeInfo,
1019    data_type: Option<glib::Type>,
1020    info: *mut ffi::GstPadProbeInfo,
1021) {
1022    if ret == PadProbeReturn::Handled {
1023        // Handled queries need to be returned
1024        // Handled buffers and buffer lists are consumed
1025        // No other types can safely be used here
1026
1027        match probe_info.data {
1028            Some(PadProbeData::Query(query)) => {
1029                assert_eq!(data_type, Some(Query::static_type()));
1030                (*info).data = query.as_mut_ptr() as *mut libc::c_void;
1031            }
1032            Some(PadProbeData::Buffer(_)) => {
1033                assert_eq!(data_type, Some(Buffer::static_type()));
1034                // Buffer not consumed by probe; consume it here
1035            }
1036            Some(PadProbeData::BufferList(_)) => {
1037                assert_eq!(data_type, Some(BufferList::static_type()));
1038                // BufferList not consumed by probe; consume it here
1039            }
1040            Some(PadProbeData::Event(_)) => {
1041                assert_eq!(data_type, Some(Event::static_type()));
1042                // Event not consumed by probe; consume it here
1043            }
1044            None if data_type == Some(Buffer::static_type())
1045                || data_type == Some(BufferList::static_type())
1046                || data_type == Some(Event::static_type()) =>
1047            {
1048                // Buffer or Event consumed by probe
1049                (*info).data = ptr::null_mut();
1050            }
1051            other => panic!("Bad data for {data_type:?} pad probe returning Handled: {other:?}"),
1052        }
1053    } else if ret == PadProbeReturn::Drop {
1054        // We may have consumed the object via PadProbeInfo::take_*() functions
1055        match probe_info.data {
1056            None if data_type == Some(Buffer::static_type())
1057                || data_type == Some(BufferList::static_type())
1058                || data_type == Some(Event::static_type()) =>
1059            {
1060                (*info).data = ptr::null_mut();
1061            }
1062            _ => {
1063                // Nothing to do, it's going to be dropped
1064            }
1065        }
1066    } else {
1067        match probe_info.data {
1068            Some(PadProbeData::Buffer(buffer)) => {
1069                assert_eq!(data_type, Some(Buffer::static_type()));
1070                (*info).data = buffer.into_glib_ptr() as *mut libc::c_void;
1071            }
1072            Some(PadProbeData::BufferList(bufferlist)) => {
1073                assert_eq!(data_type, Some(BufferList::static_type()));
1074                (*info).data = bufferlist.into_glib_ptr() as *mut libc::c_void;
1075            }
1076            Some(PadProbeData::Event(event)) => {
1077                assert_eq!(data_type, Some(Event::static_type()));
1078                (*info).data = event.into_glib_ptr() as *mut libc::c_void;
1079            }
1080            Some(PadProbeData::Query(query)) => {
1081                assert_eq!(data_type, Some(Query::static_type()));
1082                (*info).data = query.as_mut_ptr() as *mut libc::c_void;
1083            }
1084            Some(PadProbeData::__Unknown(ptr)) => {
1085                assert_eq!(data_type, None);
1086                (*info).data = ptr as *mut libc::c_void;
1087            }
1088            None => {
1089                assert_eq!(data_type, None);
1090            }
1091        }
1092    }
1093
1094    let flow_ret: FlowReturn = probe_info.flow_res.into();
1095    (*info).ABI.abi.flow_ret = flow_ret.into_glib();
1096}
1097
1098unsafe extern "C" fn trampoline_pad_probe<
1099    T,
1100    F: Fn(&T, &mut PadProbeInfo) -> PadProbeReturn + Send + Sync + 'static,
1101>(
1102    pad: *mut ffi::GstPad,
1103    info: *mut ffi::GstPadProbeInfo,
1104    func: gpointer,
1105) -> ffi::GstPadProbeReturn
1106where
1107    T: IsA<Pad>,
1108{
1109    let func: &F = &*(func as *const F);
1110
1111    let (mut probe_info, data_type) = create_probe_info(info);
1112
1113    let ret = func(
1114        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1115        &mut probe_info,
1116    );
1117
1118    update_probe_info(ret, probe_info, data_type, info);
1119
1120    ret.into_glib()
1121}
1122
1123unsafe extern "C" fn trampoline_activate_function<
1124    T,
1125    F: Fn(&T, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static,
1126>(
1127    pad: *mut ffi::GstPad,
1128    parent: *mut ffi::GstObject,
1129) -> glib::ffi::gboolean
1130where
1131    T: IsA<Pad>,
1132{
1133    let func: &F = &*((*pad).activatedata as *const F);
1134
1135    match func(
1136        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1137        Option::<crate::Object>::from_glib_borrow(parent)
1138            .as_ref()
1139            .as_ref(),
1140    ) {
1141        Ok(()) => true,
1142        Err(err) => {
1143            err.log_with_object(&*Pad::from_glib_borrow(pad));
1144            false
1145        }
1146    }
1147    .into_glib()
1148}
1149
1150unsafe extern "C" fn trampoline_activatemode_function<
1151    T,
1152    F: Fn(&T, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError>
1153        + Send
1154        + Sync
1155        + 'static,
1156>(
1157    pad: *mut ffi::GstPad,
1158    parent: *mut ffi::GstObject,
1159    mode: ffi::GstPadMode,
1160    active: glib::ffi::gboolean,
1161) -> glib::ffi::gboolean
1162where
1163    T: IsA<Pad>,
1164{
1165    let func: &F = &*((*pad).activatemodedata as *const F);
1166
1167    match func(
1168        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1169        Option::<crate::Object>::from_glib_borrow(parent)
1170            .as_ref()
1171            .as_ref(),
1172        from_glib(mode),
1173        from_glib(active),
1174    ) {
1175        Ok(()) => true,
1176        Err(err) => {
1177            err.log_with_object(&*Pad::from_glib_borrow(pad));
1178            false
1179        }
1180    }
1181    .into_glib()
1182}
1183
1184unsafe extern "C" fn trampoline_chain_function<
1185    T,
1186    F: Fn(&T, Option<&crate::Object>, crate::Buffer) -> Result<FlowSuccess, FlowError>
1187        + Send
1188        + Sync
1189        + 'static,
1190>(
1191    pad: *mut ffi::GstPad,
1192    parent: *mut ffi::GstObject,
1193    buffer: *mut ffi::GstBuffer,
1194) -> ffi::GstFlowReturn
1195where
1196    T: IsA<Pad>,
1197{
1198    let func: &F = &*((*pad).chaindata as *const F);
1199
1200    let res: FlowReturn = func(
1201        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1202        Option::<crate::Object>::from_glib_borrow(parent)
1203            .as_ref()
1204            .as_ref(),
1205        from_glib_full(buffer),
1206    )
1207    .into();
1208    res.into_glib()
1209}
1210
1211unsafe extern "C" fn trampoline_chain_list_function<
1212    T,
1213    F: Fn(&T, Option<&crate::Object>, crate::BufferList) -> Result<FlowSuccess, FlowError>
1214        + Send
1215        + Sync
1216        + 'static,
1217>(
1218    pad: *mut ffi::GstPad,
1219    parent: *mut ffi::GstObject,
1220    list: *mut ffi::GstBufferList,
1221) -> ffi::GstFlowReturn
1222where
1223    T: IsA<Pad>,
1224{
1225    let func: &F = &*((*pad).chainlistdata as *const F);
1226
1227    let res: FlowReturn = func(
1228        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1229        Option::<crate::Object>::from_glib_borrow(parent)
1230            .as_ref()
1231            .as_ref(),
1232        from_glib_full(list),
1233    )
1234    .into();
1235    res.into_glib()
1236}
1237
1238unsafe extern "C" fn trampoline_event_function<
1239    T,
1240    F: Fn(&T, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static,
1241>(
1242    pad: *mut ffi::GstPad,
1243    parent: *mut ffi::GstObject,
1244    event: *mut ffi::GstEvent,
1245) -> glib::ffi::gboolean
1246where
1247    T: IsA<Pad>,
1248{
1249    let func: &F = &*((*pad).eventdata as *const F);
1250
1251    func(
1252        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1253        Option::<crate::Object>::from_glib_borrow(parent)
1254            .as_ref()
1255            .as_ref(),
1256        from_glib_full(event),
1257    )
1258    .into_glib()
1259}
1260
1261unsafe extern "C" fn trampoline_event_full_function<
1262    T,
1263    F: Fn(&T, Option<&crate::Object>, crate::Event) -> Result<FlowSuccess, FlowError>
1264        + Send
1265        + Sync
1266        + 'static,
1267>(
1268    pad: *mut ffi::GstPad,
1269    parent: *mut ffi::GstObject,
1270    event: *mut ffi::GstEvent,
1271) -> ffi::GstFlowReturn
1272where
1273    T: IsA<Pad>,
1274{
1275    let func: &F = &*((*pad).eventdata as *const F);
1276
1277    let res: FlowReturn = func(
1278        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1279        Option::<crate::Object>::from_glib_borrow(parent)
1280            .as_ref()
1281            .as_ref(),
1282        from_glib_full(event),
1283    )
1284    .into();
1285    res.into_glib()
1286}
1287
1288#[allow(clippy::needless_option_as_deref)]
1289unsafe extern "C" fn trampoline_getrange_function<
1290    T,
1291    F: Fn(
1292            &T,
1293            Option<&crate::Object>,
1294            u64,
1295            Option<&mut crate::BufferRef>,
1296            u32,
1297        ) -> Result<PadGetRangeSuccess, crate::FlowError>
1298        + Send
1299        + Sync
1300        + 'static,
1301>(
1302    pad: *mut ffi::GstPad,
1303    parent: *mut ffi::GstObject,
1304    offset: u64,
1305    length: u32,
1306    buffer: *mut *mut ffi::GstBuffer,
1307) -> ffi::GstFlowReturn
1308where
1309    T: IsA<Pad>,
1310{
1311    let func: &F = &*((*pad).getrangedata as *const F);
1312
1313    debug_assert!(!buffer.is_null());
1314
1315    let pad = Pad::from_glib_borrow(pad);
1316    let pad = pad.unsafe_cast_ref();
1317    let mut passed_buffer = if (*buffer).is_null() {
1318        None
1319    } else {
1320        Some(crate::BufferRef::from_mut_ptr(*buffer))
1321    };
1322
1323    match func(
1324        pad,
1325        Option::<crate::Object>::from_glib_borrow(parent)
1326            .as_ref()
1327            .as_ref(),
1328        offset,
1329        passed_buffer.as_deref_mut(),
1330        length,
1331    ) {
1332        Ok(PadGetRangeSuccess::NewBuffer(new_buffer)) => {
1333            if let Some(passed_buffer) = passed_buffer {
1334                crate::debug!(
1335                    crate::CAT_PERFORMANCE,
1336                    obj = pad.unsafe_cast_ref::<glib::Object>(),
1337                    "Returned new buffer from getrange function, copying into passed buffer"
1338                );
1339
1340                let mut map = match passed_buffer.map_writable() {
1341                    Ok(map) => map,
1342                    Err(_) => {
1343                        crate::error!(
1344                            crate::CAT_RUST,
1345                            obj = pad.unsafe_cast_ref::<glib::Object>(),
1346                            "Failed to map passed buffer writable"
1347                        );
1348                        return ffi::GST_FLOW_ERROR;
1349                    }
1350                };
1351
1352                let copied_size = new_buffer.copy_to_slice(0, &mut map);
1353                drop(map);
1354
1355                if let Err(copied_size) = copied_size {
1356                    passed_buffer.set_size(copied_size);
1357                }
1358
1359                match new_buffer.copy_into(passed_buffer, crate::BUFFER_COPY_METADATA, ..) {
1360                    Ok(_) => FlowReturn::Ok.into_glib(),
1361                    Err(_) => {
1362                        crate::error!(
1363                            crate::CAT_RUST,
1364                            obj = pad.unsafe_cast_ref::<glib::Object>(),
1365                            "Failed to copy buffer metadata"
1366                        );
1367
1368                        FlowReturn::Error.into_glib()
1369                    }
1370                }
1371            } else {
1372                *buffer = new_buffer.into_glib_ptr();
1373                FlowReturn::Ok.into_glib()
1374            }
1375        }
1376        Ok(PadGetRangeSuccess::FilledBuffer) => {
1377            assert!(passed_buffer.is_some());
1378            FlowReturn::Ok.into_glib()
1379        }
1380        Err(ret) => FlowReturn::from_error(ret).into_glib(),
1381    }
1382}
1383
1384unsafe extern "C" fn trampoline_iterate_internal_links_function<
1385    T,
1386    F: Fn(&T, Option<&crate::Object>) -> crate::Iterator<Pad> + Send + Sync + 'static,
1387>(
1388    pad: *mut ffi::GstPad,
1389    parent: *mut ffi::GstObject,
1390) -> *mut ffi::GstIterator
1391where
1392    T: IsA<Pad>,
1393{
1394    let func: &F = &*((*pad).iterintlinkdata as *const F);
1395
1396    // Steal the iterator and return it
1397    let ret = func(
1398        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1399        Option::<crate::Object>::from_glib_borrow(parent)
1400            .as_ref()
1401            .as_ref(),
1402    );
1403
1404    ret.into_glib_ptr()
1405}
1406
1407unsafe extern "C" fn trampoline_link_function<
1408    T,
1409    F: Fn(
1410            &T,
1411            Option<&crate::Object>,
1412            &crate::Pad,
1413        ) -> Result<crate::PadLinkSuccess, crate::PadLinkError>
1414        + Send
1415        + Sync
1416        + 'static,
1417>(
1418    pad: *mut ffi::GstPad,
1419    parent: *mut ffi::GstObject,
1420    peer: *mut ffi::GstPad,
1421) -> ffi::GstPadLinkReturn
1422where
1423    T: IsA<Pad>,
1424{
1425    let func: &F = &*((*pad).linkdata as *const F);
1426
1427    let res: crate::PadLinkReturn = func(
1428        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1429        Option::<crate::Object>::from_glib_borrow(parent)
1430            .as_ref()
1431            .as_ref(),
1432        &from_glib_borrow(peer),
1433    )
1434    .into();
1435    res.into_glib()
1436}
1437
1438unsafe extern "C" fn trampoline_query_function<
1439    T,
1440    F: Fn(&T, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static,
1441>(
1442    pad: *mut ffi::GstPad,
1443    parent: *mut ffi::GstObject,
1444    query: *mut ffi::GstQuery,
1445) -> glib::ffi::gboolean
1446where
1447    T: IsA<Pad>,
1448{
1449    let func: &F = &*((*pad).querydata as *const F);
1450
1451    func(
1452        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1453        Option::<crate::Object>::from_glib_borrow(parent)
1454            .as_ref()
1455            .as_ref(),
1456        crate::QueryRef::from_mut_ptr(query),
1457    )
1458    .into_glib()
1459}
1460
1461unsafe extern "C" fn trampoline_unlink_function<
1462    T,
1463    F: Fn(&T, Option<&crate::Object>) + Send + Sync + 'static,
1464>(
1465    pad: *mut ffi::GstPad,
1466    parent: *mut ffi::GstObject,
1467) where
1468    T: IsA<Pad>,
1469{
1470    let func: &F = &*((*pad).unlinkdata as *const F);
1471
1472    func(
1473        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1474        Option::<crate::Object>::from_glib_borrow(parent)
1475            .as_ref()
1476            .as_ref(),
1477    )
1478}
1479
1480unsafe extern "C" fn destroy_closure<F>(ptr: gpointer) {
1481    let _ = Box::<F>::from_raw(ptr as *mut _);
1482}
1483
1484impl Pad {
1485    // rustdoc-stripper-ignore-next
1486    /// Creates a new [`Pad`] with the specified [`PadDirection`](crate::PadDirection).
1487    ///
1488    /// The [`Pad`] will be assigned the usual `gst::Object` generated unique name.
1489    ///
1490    /// Use [`Pad::builder()`] to get a [`PadBuilder`] and define options.
1491    #[doc(alias = "gst_pad_new")]
1492    pub fn new(direction: crate::PadDirection) -> Self {
1493        skip_assert_initialized!();
1494        Self::builder(direction).build()
1495    }
1496
1497    // rustdoc-stripper-ignore-next
1498    /// Creates a [`PadBuilder`] with the specified [`PadDirection`](crate::PadDirection).
1499    #[doc(alias = "gst_pad_new")]
1500    pub fn builder(direction: crate::PadDirection) -> PadBuilder<Self> {
1501        skip_assert_initialized!();
1502        PadBuilder::new(direction)
1503    }
1504
1505    // rustdoc-stripper-ignore-next
1506    /// Creates a new [`Pad`] from the [`StaticPadTemplate`](crate::StaticPadTemplate).
1507    ///
1508    /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`,
1509    /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1510    /// the `Pad` will automatically be named after the `name_template`.
1511    ///
1512    /// Use [`Pad::builder_from_static_template()`] to get a [`PadBuilder`] and define options.
1513    ///
1514    /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object`
1515    /// automatically generated unique name.
1516    ///
1517    /// # Panics
1518    ///
1519    /// Panics if the `name_template` is a wildcard-name.
1520    #[doc(alias = "gst_pad_new_from_static_template")]
1521    pub fn from_static_template(templ: &StaticPadTemplate) -> Self {
1522        skip_assert_initialized!();
1523        Self::builder_from_static_template(templ).build()
1524    }
1525
1526    // rustdoc-stripper-ignore-next
1527    /// Creates a new [`PadBuilder`] from the [`StaticPadTemplate`](crate::StaticPadTemplate).
1528    ///
1529    /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`,
1530    /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1531    /// the `Pad` will automatically be named after the `name_template`.
1532    ///
1533    /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object`
1534    /// automatically generated unique name.
1535    #[doc(alias = "gst_pad_new_from_static_template")]
1536    pub fn builder_from_static_template(templ: &StaticPadTemplate) -> PadBuilder<Self> {
1537        skip_assert_initialized!();
1538        PadBuilder::from_static_template(templ)
1539    }
1540
1541    // rustdoc-stripper-ignore-next
1542    /// Creates a new [`Pad`] from the [`PadTemplate`](crate::PadTemplate).
1543    ///
1544    /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`,
1545    /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1546    /// the `Pad` will automatically be named after the `name_template`.
1547    ///
1548    /// Use [`Pad::builder_from_template()`] to get a [`PadBuilder`] and define options.
1549    ///
1550    /// # Panics
1551    ///
1552    /// Panics if the `name_template` is a wildcard-name.
1553    #[doc(alias = "gst_pad_new_from_template")]
1554    pub fn from_template(templ: &crate::PadTemplate) -> Self {
1555        skip_assert_initialized!();
1556        Self::builder_from_template(templ).build()
1557    }
1558
1559    // rustdoc-stripper-ignore-next
1560    /// Creates a new [`PadBuilder`] from the [`PadTemplate`](crate::PadTemplate).
1561    ///
1562    /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`,
1563    /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1564    /// the `Pad` will automatically be named after the `name_template`.
1565    ///
1566    /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object`
1567    /// automatically generated unique name.
1568    #[doc(alias = "gst_pad_new_from_template")]
1569    pub fn builder_from_template(templ: &crate::PadTemplate) -> PadBuilder<Self> {
1570        skip_assert_initialized!();
1571        PadBuilder::from_template(templ)
1572    }
1573
1574    #[doc(alias = "gst_pad_query_default")]
1575    pub fn query_default<O: IsA<Pad>>(
1576        pad: &O,
1577        parent: Option<&impl IsA<crate::Object>>,
1578        query: &mut QueryRef,
1579    ) -> bool {
1580        skip_assert_initialized!();
1581        unsafe {
1582            from_glib(ffi::gst_pad_query_default(
1583                pad.as_ref().to_glib_none().0,
1584                parent.map(|p| p.as_ref()).to_glib_none().0,
1585                query.as_mut_ptr(),
1586            ))
1587        }
1588    }
1589
1590    #[doc(alias = "gst_pad_event_default")]
1591    pub fn event_default<O: IsA<Pad>>(
1592        pad: &O,
1593        parent: Option<&impl IsA<crate::Object>>,
1594        event: impl Into<Event>,
1595    ) -> bool {
1596        skip_assert_initialized!();
1597        unsafe {
1598            from_glib(ffi::gst_pad_event_default(
1599                pad.as_ref().to_glib_none().0,
1600                parent.map(|p| p.as_ref()).to_glib_none().0,
1601                event.into().into_glib_ptr(),
1602            ))
1603        }
1604    }
1605
1606    #[doc(alias = "gst_pad_iterate_internal_links_default")]
1607    pub fn iterate_internal_links_default<O: IsA<Pad>>(
1608        pad: &O,
1609        parent: Option<&impl IsA<crate::Object>>,
1610    ) -> crate::Iterator<Pad> {
1611        skip_assert_initialized!();
1612        unsafe {
1613            from_glib_full(ffi::gst_pad_iterate_internal_links_default(
1614                pad.as_ref().to_glib_none().0,
1615                parent.map(|p| p.as_ref()).to_glib_none().0,
1616            ))
1617        }
1618    }
1619}
1620
1621pub(crate) enum PadBuilderName {
1622    Undefined,
1623    KeepGenerated,
1624    UserDefined(String),
1625    CandidateForWildcardTemplate(String),
1626}
1627
1628#[must_use = "The builder must be built to be used"]
1629pub struct PadBuilder<T> {
1630    pub(crate) pad: T,
1631    pub(crate) name: PadBuilderName,
1632}
1633
1634impl<T: IsA<Pad> + IsA<glib::Object> + glib::object::IsClass> PadBuilder<T> {
1635    // rustdoc-stripper-ignore-next
1636    /// Creates a `PadBuilder` with the specified [`PadDirection`](crate::PadDirection).
1637    pub fn new(direction: crate::PadDirection) -> Self {
1638        assert_initialized_main_thread!();
1639
1640        let pad = glib::Object::builder::<T>()
1641            .property("direction", direction)
1642            .build();
1643
1644        // Ghost pads are a bit special
1645        if let Some(pad) = pad.dynamic_cast_ref::<crate::GhostPad>() {
1646            unsafe {
1647                let res = ffi::gst_ghost_pad_construct(pad.to_glib_none().0);
1648                // This can't really fail...
1649                debug_assert_ne!(res, glib::ffi::GFALSE, "Failed to construct ghost pad");
1650            }
1651        }
1652
1653        PadBuilder {
1654            pad,
1655            name: PadBuilderName::Undefined,
1656        }
1657    }
1658
1659    // rustdoc-stripper-ignore-next
1660    /// Creates a `PadBuilder` from the specified [`StaticPadTemplate`](crate::StaticPadTemplate).
1661    ///
1662    /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`,
1663    /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1664    /// the `Pad` will automatically be named after the `name_template`.
1665    ///
1666    /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object`
1667    /// automatically generated unique name.
1668    pub fn from_static_template(templ: &StaticPadTemplate) -> Self {
1669        skip_assert_initialized!();
1670
1671        let templ = templ.get();
1672        Self::from_template(&templ)
1673    }
1674
1675    // rustdoc-stripper-ignore-next
1676    /// Creates a `PadBuilder` from the specified [`PadTemplate`](crate::PadTemplate).
1677    ///
1678    /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`,
1679    /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1680    /// the `Pad` will automatically be named after the `name_template`.
1681    ///
1682    /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object`
1683    /// automatically generated unique name.
1684    pub fn from_template(templ: &crate::PadTemplate) -> Self {
1685        assert_initialized_main_thread!();
1686
1687        let mut type_ = T::static_type();
1688        let gtype = templ.gtype();
1689
1690        if gtype == glib::Type::UNIT {
1691            // Nothing to be done, we can create any kind of pad
1692        } else if gtype.is_a(type_) {
1693            // We were asked to create a parent type of the template type, e.g. a gst::Pad for
1694            // a template that wants a gst_base::AggregatorPad. Not a problem: update the type
1695            type_ = gtype;
1696        } else {
1697            // Otherwise the requested type must be a subclass of the template pad type
1698            assert!(type_.is_a(gtype));
1699        }
1700
1701        let mut properties = [
1702            ("direction", templ.direction().into()),
1703            ("template", templ.into()),
1704        ];
1705
1706        let pad =
1707            unsafe { glib::Object::with_mut_values(type_, &mut properties).unsafe_cast::<T>() };
1708
1709        // Ghost pads are a bit special
1710        if let Some(pad) = pad.dynamic_cast_ref::<crate::GhostPad>() {
1711            unsafe {
1712                let res = ffi::gst_ghost_pad_construct(pad.to_glib_none().0);
1713                // This can't really fail...
1714                debug_assert_ne!(res, glib::ffi::GFALSE, "Failed to construct ghost pad");
1715            }
1716        }
1717
1718        PadBuilder {
1719            pad,
1720            name: PadBuilderName::Undefined,
1721        }
1722    }
1723
1724    // rustdoc-stripper-ignore-next
1725    /// Uses the `gst::Object` generated unique name.
1726    pub fn generated_name(mut self) -> Self {
1727        self.name = PadBuilderName::KeepGenerated;
1728        self
1729    }
1730
1731    // rustdoc-stripper-ignore-next
1732    /// Sets the name of the Pad.
1733    pub fn name(mut self, name: impl Into<String>) -> Self {
1734        self.name = PadBuilderName::UserDefined(name.into());
1735
1736        self
1737    }
1738
1739    // rustdoc-stripper-ignore-next
1740    /// Optionally sets the name of the Pad.
1741    ///
1742    /// This method is convenient when the `name` is provided as an `Option`.
1743    /// If the `name` is `None`, this has no effect.
1744    #[deprecated = "use `name_if_some()` instead"]
1745    pub fn maybe_name<N: Into<String>>(self, name: Option<N>) -> Self {
1746        if let Some(name) = name {
1747            self.name(name)
1748        } else {
1749            self
1750        }
1751    }
1752
1753    // rustdoc-stripper-ignore-next
1754    /// Optionally sets the name of the Pad.
1755    ///
1756    /// This method is convenient when the `name` is provided as an `Option`.
1757    /// If the `name` is `None`, this has no effect.
1758    pub fn name_if_some<N: Into<String>>(self, name: Option<N>) -> Self {
1759        if let Some(name) = name {
1760            self.name(name)
1761        } else {
1762            self
1763        }
1764    }
1765
1766    #[doc(alias = "gst_pad_set_activate_function")]
1767    pub fn activate_function<F>(self, func: F) -> Self
1768    where
1769        F: Fn(&T, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static,
1770    {
1771        unsafe {
1772            self.pad.set_activate_function(func);
1773        }
1774
1775        self
1776    }
1777
1778    #[doc(alias = "gst_pad_set_activate_function")]
1779    pub fn activate_function_if_some<F>(self, func: Option<F>) -> Self
1780    where
1781        F: Fn(&T, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static,
1782    {
1783        if let Some(func) = func {
1784            self.activate_function(func)
1785        } else {
1786            self
1787        }
1788    }
1789
1790    #[doc(alias = "gst_pad_set_activatemode_function")]
1791    pub fn activatemode_function<F>(self, func: F) -> Self
1792    where
1793        F: Fn(&T, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError>
1794            + Send
1795            + Sync
1796            + 'static,
1797    {
1798        unsafe {
1799            self.pad.set_activatemode_function(func);
1800        }
1801
1802        self
1803    }
1804
1805    #[doc(alias = "gst_pad_set_activatemode_function")]
1806    pub fn activatemode_function_if_some<F>(self, func: Option<F>) -> Self
1807    where
1808        F: Fn(&T, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError>
1809            + Send
1810            + Sync
1811            + 'static,
1812    {
1813        if let Some(func) = func {
1814            self.activatemode_function(func)
1815        } else {
1816            self
1817        }
1818    }
1819
1820    #[doc(alias = "gst_pad_set_chain_function")]
1821    pub fn chain_function<F>(self, func: F) -> Self
1822    where
1823        F: Fn(&T, Option<&crate::Object>, crate::Buffer) -> Result<FlowSuccess, FlowError>
1824            + Send
1825            + Sync
1826            + 'static,
1827    {
1828        unsafe {
1829            self.pad.set_chain_function(func);
1830        }
1831
1832        self
1833    }
1834
1835    #[doc(alias = "gst_pad_set_chain_function")]
1836    pub fn chain_function_if_some<F>(self, func: Option<F>) -> Self
1837    where
1838        F: Fn(&T, Option<&crate::Object>, crate::Buffer) -> Result<FlowSuccess, FlowError>
1839            + Send
1840            + Sync
1841            + 'static,
1842    {
1843        if let Some(func) = func {
1844            self.chain_function(func)
1845        } else {
1846            self
1847        }
1848    }
1849
1850    #[doc(alias = "gst_pad_set_chain_list_function")]
1851    pub fn chain_list_function<F>(self, func: F) -> Self
1852    where
1853        F: Fn(&T, Option<&crate::Object>, crate::BufferList) -> Result<FlowSuccess, FlowError>
1854            + Send
1855            + Sync
1856            + 'static,
1857    {
1858        unsafe {
1859            self.pad.set_chain_list_function(func);
1860        }
1861
1862        self
1863    }
1864
1865    #[doc(alias = "gst_pad_set_chain_list_function")]
1866    pub fn chain_list_function_if_some<F>(self, func: Option<F>) -> Self
1867    where
1868        F: Fn(&T, Option<&crate::Object>, crate::BufferList) -> Result<FlowSuccess, FlowError>
1869            + Send
1870            + Sync
1871            + 'static,
1872    {
1873        if let Some(func) = func {
1874            self.chain_list_function(func)
1875        } else {
1876            self
1877        }
1878    }
1879
1880    #[doc(alias = "gst_pad_set_event_function")]
1881    pub fn event_function<F>(self, func: F) -> Self
1882    where
1883        F: Fn(&T, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static,
1884    {
1885        unsafe {
1886            self.pad.set_event_function(func);
1887        }
1888
1889        self
1890    }
1891
1892    #[doc(alias = "gst_pad_set_event_function")]
1893    pub fn event_function_if_some<F>(self, func: Option<F>) -> Self
1894    where
1895        F: Fn(&T, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static,
1896    {
1897        if let Some(func) = func {
1898            self.event_function(func)
1899        } else {
1900            self
1901        }
1902    }
1903
1904    #[doc(alias = "gst_pad_set_event_full_function")]
1905    pub fn event_full_function<F>(self, func: F) -> Self
1906    where
1907        F: Fn(&T, Option<&crate::Object>, crate::Event) -> Result<FlowSuccess, FlowError>
1908            + Send
1909            + Sync
1910            + 'static,
1911    {
1912        unsafe {
1913            self.pad.set_event_full_function(func);
1914        }
1915
1916        self
1917    }
1918
1919    #[doc(alias = "gst_pad_set_event_full_function")]
1920    pub fn event_full_function_if_some<F>(self, func: Option<F>) -> Self
1921    where
1922        F: Fn(&T, Option<&crate::Object>, crate::Event) -> Result<FlowSuccess, FlowError>
1923            + Send
1924            + Sync
1925            + 'static,
1926    {
1927        if let Some(func) = func {
1928            self.event_full_function(func)
1929        } else {
1930            self
1931        }
1932    }
1933
1934    #[doc(alias = "gst_pad_set_getrange_function")]
1935    pub fn getrange_function<F>(self, func: F) -> Self
1936    where
1937        F: Fn(
1938                &T,
1939                Option<&crate::Object>,
1940                u64,
1941                Option<&mut crate::BufferRef>,
1942                u32,
1943            ) -> Result<PadGetRangeSuccess, crate::FlowError>
1944            + Send
1945            + Sync
1946            + 'static,
1947    {
1948        unsafe {
1949            self.pad.set_getrange_function(func);
1950        }
1951
1952        self
1953    }
1954
1955    #[doc(alias = "gst_pad_set_getrange_function")]
1956    pub fn getrange_function_if_some<F>(self, func: Option<F>) -> Self
1957    where
1958        F: Fn(
1959                &T,
1960                Option<&crate::Object>,
1961                u64,
1962                Option<&mut crate::BufferRef>,
1963                u32,
1964            ) -> Result<PadGetRangeSuccess, crate::FlowError>
1965            + Send
1966            + Sync
1967            + 'static,
1968    {
1969        if let Some(func) = func {
1970            self.getrange_function(func)
1971        } else {
1972            self
1973        }
1974    }
1975
1976    #[doc(alias = "gst_pad_set_iterate_internal_links_function")]
1977    pub fn iterate_internal_links_function<F>(self, func: F) -> Self
1978    where
1979        F: Fn(&T, Option<&crate::Object>) -> crate::Iterator<Pad> + Send + Sync + 'static,
1980    {
1981        unsafe {
1982            self.pad.set_iterate_internal_links_function(func);
1983        }
1984
1985        self
1986    }
1987
1988    #[doc(alias = "gst_pad_set_iterate_internal_links_function")]
1989    pub fn iterate_internal_links_function_if_some<F>(self, func: Option<F>) -> Self
1990    where
1991        F: Fn(&T, Option<&crate::Object>) -> crate::Iterator<Pad> + Send + Sync + 'static,
1992    {
1993        if let Some(func) = func {
1994            self.iterate_internal_links_function(func)
1995        } else {
1996            self
1997        }
1998    }
1999
2000    #[doc(alias = "gst_pad_set_link_function")]
2001    pub fn link_function<F>(self, func: F) -> Self
2002    where
2003        F: Fn(
2004                &T,
2005                Option<&crate::Object>,
2006                &Pad,
2007            ) -> Result<crate::PadLinkSuccess, crate::PadLinkError>
2008            + Send
2009            + Sync
2010            + 'static,
2011    {
2012        unsafe {
2013            self.pad.set_link_function(func);
2014        }
2015
2016        self
2017    }
2018
2019    #[doc(alias = "gst_pad_set_link_function")]
2020    pub fn link_function_if_some<F>(self, func: Option<F>) -> Self
2021    where
2022        F: Fn(
2023                &T,
2024                Option<&crate::Object>,
2025                &Pad,
2026            ) -> Result<crate::PadLinkSuccess, crate::PadLinkError>
2027            + Send
2028            + Sync
2029            + 'static,
2030    {
2031        if let Some(func) = func {
2032            self.link_function(func)
2033        } else {
2034            self
2035        }
2036    }
2037
2038    #[doc(alias = "gst_pad_set_query_function")]
2039    pub fn query_function<F>(self, func: F) -> Self
2040    where
2041        F: Fn(&T, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static,
2042    {
2043        unsafe {
2044            self.pad.set_query_function(func);
2045        }
2046
2047        self
2048    }
2049
2050    #[doc(alias = "gst_pad_set_query_function")]
2051    pub fn query_function_if_some<F>(self, func: Option<F>) -> Self
2052    where
2053        F: Fn(&T, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static,
2054    {
2055        if let Some(func) = func {
2056            self.query_function(func)
2057        } else {
2058            self
2059        }
2060    }
2061
2062    #[doc(alias = "gst_pad_set_unlink_function")]
2063    pub fn unlink_function<F>(self, func: F) -> Self
2064    where
2065        F: Fn(&T, Option<&crate::Object>) + Send + Sync + 'static,
2066    {
2067        unsafe {
2068            self.pad.set_unlink_function(func);
2069        }
2070
2071        self
2072    }
2073
2074    #[doc(alias = "gst_pad_set_unlink_function")]
2075    pub fn unlink_function_if_some<F>(self, func: Option<F>) -> Self
2076    where
2077        F: Fn(&T, Option<&crate::Object>) + Send + Sync + 'static,
2078    {
2079        if let Some(func) = func {
2080            self.unlink_function(func)
2081        } else {
2082            self
2083        }
2084    }
2085
2086    pub fn flags(self, flags: PadFlags) -> Self {
2087        self.pad.set_pad_flags(flags);
2088
2089        self
2090    }
2091
2092    pub fn flags_if_some(self, flags: Option<PadFlags>) -> Self {
2093        if let Some(flags) = flags {
2094            self.flags(flags)
2095        } else {
2096            self
2097        }
2098    }
2099
2100    // rustdoc-stripper-ignore-next
2101    /// Builds the [`Pad`].
2102    ///
2103    /// # Panics
2104    ///
2105    /// Panics if the [`Pad`] was built from a [`PadTemplate`](crate::PadTemplate)
2106    /// with a wildcard-name `name_template` (i.e. containing `%u`, `%s` or `%d`)
2107    /// and no specific `name` was provided using [`PadBuilder::name`]
2108    /// or [`PadBuilder::name_if_some`], or for [`GhostPad`s](crate::GhostPad),
2109    /// by defining a `target`.
2110    ///
2111    /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object`
2112    /// automatically generated unique name.
2113    #[must_use = "Building the pad without using it has no effect"]
2114    #[track_caller]
2115    pub fn build(self) -> T {
2116        let Self { pad, name } = self;
2117
2118        let templ = pad.pad_template();
2119
2120        use PadBuilderName::*;
2121        match (name, templ) {
2122            (KeepGenerated, _) => (),
2123            (Undefined, None) => (),
2124            (Undefined, Some(templ)) => {
2125                if templ.name().find('%').is_some() {
2126                    panic!(concat!(
2127                        "Attempt to build a Pad from a wildcard-name template",
2128                        " or with a target Pad with an incompatible name.",
2129                        " Make sure to define a specific name using PadBuilder",
2130                        " or opt-in to keep the automatically generated name.",
2131                    ));
2132                } else {
2133                    pad.set_property("name", templ.name());
2134                }
2135            }
2136            (UserDefined(name), _) | (CandidateForWildcardTemplate(name), None) => {
2137                pad.set_property("name", name);
2138            }
2139            (CandidateForWildcardTemplate(name), Some(templ)) => {
2140                if templ.name().find('%').is_none() {
2141                    // Not a widlcard template
2142                    pad.set_property("name", templ.name());
2143                } else {
2144                    let mut can_assign_name = true;
2145
2146                    if templ.presence() == crate::PadPresence::Request {
2147                        // Check if the name is compatible with the name template.
2148                        use crate::CAT_RUST;
2149
2150                        let mut name_parts = name.split('_');
2151                        for templ_part in templ.name_template().split('_') {
2152                            let Some(name_part) = name_parts.next() else {
2153                                crate::debug!(
2154                                CAT_RUST,
2155                                "Not using Pad name '{name}': not enough parts compared to template '{}'",
2156                                templ.name_template(),
2157                            );
2158                                can_assign_name = false;
2159                                break;
2160                            };
2161
2162                            if let Some(conv_spec_start) = templ_part.find('%') {
2163                                if conv_spec_start > 0
2164                                    && !name_part.starts_with(&templ_part[..conv_spec_start])
2165                                {
2166                                    crate::debug!(
2167                                    CAT_RUST,
2168                                    "Not using Pad name '{name}': mismatch template '{}' prefix",
2169                                    templ.name_template(),
2170                                );
2171                                    can_assign_name = false;
2172                                    break;
2173                                }
2174
2175                                let conv_spec_pos = conv_spec_start + 1;
2176                                match templ_part.get(conv_spec_pos..=conv_spec_pos) {
2177                                    Some("s") => {
2178                                        // *There can be only one* %s
2179                                        break;
2180                                    }
2181                                    Some("u") => {
2182                                        if name_part
2183                                            .get(conv_spec_start..)
2184                                            .map_or(true, |s| s.parse::<u32>().is_err())
2185                                        {
2186                                            crate::debug!(
2187                                            CAT_RUST,
2188                                            "Not using Pad name '{name}': can't parse '%u' from '{name_part}' (template '{}')",
2189                                            templ.name_template(),
2190                                        );
2191
2192                                            can_assign_name = false;
2193                                            break;
2194                                        }
2195                                    }
2196                                    Some("d") => {
2197                                        if name_part
2198                                            .get(conv_spec_start..)
2199                                            .map_or(true, |s| s.parse::<i32>().is_err())
2200                                        {
2201                                            crate::debug!(
2202                                            CAT_RUST,
2203                                            "Not using target Pad name '{name}': can't parse '%i' from '{name_part}' (template '{}')",
2204                                            templ.name_template(),
2205                                        );
2206
2207                                            can_assign_name = false;
2208                                            break;
2209                                        }
2210                                    }
2211                                    other => {
2212                                        unreachable!("Unexpected conversion specifier {other:?}")
2213                                    }
2214                                }
2215                            } else if name_part != templ_part {
2216                                can_assign_name = false;
2217                            }
2218                        }
2219                    }
2220
2221                    if can_assign_name {
2222                        pad.set_property("name", name);
2223                    } else {
2224                        panic!(concat!(
2225                            "Attempt to build a Pad from a wildcard-name template",
2226                            " with a target Pad with an incompatible name.",
2227                            " Make sure to define a specific name using PadBuilder",
2228                            " or opt-in to keep the automatically generated name.",
2229                        ));
2230                    }
2231                }
2232            }
2233        }
2234
2235        pad
2236    }
2237}
2238
2239#[cfg(test)]
2240mod tests {
2241    use std::sync::{atomic::AtomicUsize, mpsc::channel, Arc, Mutex};
2242
2243    use super::*;
2244
2245    #[test]
2246    fn test_event_chain_functions() {
2247        crate::init().unwrap();
2248
2249        let events = Arc::new(Mutex::new(Vec::new()));
2250        let events_clone = events.clone();
2251        let buffers = Arc::new(Mutex::new(Vec::new()));
2252        let buffers_clone = buffers.clone();
2253        let pad = crate::Pad::builder(crate::PadDirection::Sink)
2254            .name("sink")
2255            .event_function(move |_, _, event| {
2256                let mut events = events_clone.lock().unwrap();
2257                events.push(event);
2258
2259                true
2260            })
2261            .chain_function(move |_, _, buffer| {
2262                let mut buffers = buffers_clone.lock().unwrap();
2263                buffers.push(buffer);
2264
2265                Ok(FlowSuccess::Ok)
2266            })
2267            .build();
2268
2269        pad.set_active(true).unwrap();
2270
2271        assert!(pad.send_event(crate::event::StreamStart::new("test")));
2272        let segment = crate::FormattedSegment::<crate::ClockTime>::new();
2273        assert!(pad.send_event(crate::event::Segment::new(segment.as_ref())));
2274
2275        assert_eq!(pad.chain(crate::Buffer::new()), Ok(FlowSuccess::Ok));
2276
2277        let events = events.lock().unwrap();
2278        let buffers = buffers.lock().unwrap();
2279        assert_eq!(events.len(), 2);
2280        assert_eq!(buffers.len(), 1);
2281
2282        match events[0].view() {
2283            crate::EventView::StreamStart(..) => (),
2284            _ => unreachable!(),
2285        }
2286
2287        match events[1].view() {
2288            crate::EventView::Segment(..) => (),
2289            _ => unreachable!(),
2290        }
2291    }
2292
2293    #[test]
2294    fn test_getrange_function() {
2295        crate::init().unwrap();
2296
2297        let pad = crate::Pad::builder(crate::PadDirection::Src)
2298            .name("src")
2299            .activate_function(|pad, _parent| {
2300                pad.activate_mode(crate::PadMode::Pull, true)
2301                    .map_err(|err| err.into())
2302            })
2303            .getrange_function(|_pad, _parent, offset, _buffer, size| {
2304                assert_eq!(offset, 0);
2305                assert_eq!(size, 5);
2306                let buffer = crate::Buffer::from_slice(b"abcde");
2307                Ok(PadGetRangeSuccess::NewBuffer(buffer))
2308            })
2309            .build();
2310        pad.set_active(true).unwrap();
2311
2312        let buffer = pad.range(0, 5).unwrap();
2313        let map = buffer.map_readable().unwrap();
2314        assert_eq!(&*map, b"abcde");
2315
2316        let mut buffer = crate::Buffer::with_size(5).unwrap();
2317        pad.range_fill(0, buffer.get_mut().unwrap(), 5).unwrap();
2318        let map = buffer.map_readable().unwrap();
2319        assert_eq!(&*map, b"abcde");
2320
2321        pad.set_active(false).unwrap();
2322        drop(pad);
2323
2324        let pad = crate::Pad::builder(crate::PadDirection::Src)
2325            .name("src")
2326            .activate_function(|pad, _parent| {
2327                pad.activate_mode(crate::PadMode::Pull, true)
2328                    .map_err(|err| err.into())
2329            })
2330            .getrange_function(|_pad, _parent, offset, buffer, size| {
2331                assert_eq!(offset, 0);
2332                assert_eq!(size, 5);
2333                if let Some(buffer) = buffer {
2334                    buffer.copy_from_slice(0, b"fghij").unwrap();
2335                    Ok(PadGetRangeSuccess::FilledBuffer)
2336                } else {
2337                    let buffer = crate::Buffer::from_slice(b"abcde");
2338                    Ok(PadGetRangeSuccess::NewBuffer(buffer))
2339                }
2340            })
2341            .build();
2342        pad.set_active(true).unwrap();
2343
2344        let buffer = pad.range(0, 5).unwrap();
2345        let map = buffer.map_readable().unwrap();
2346        assert_eq!(&*map, b"abcde");
2347
2348        let mut buffer = crate::Buffer::with_size(5).unwrap();
2349        pad.range_fill(0, buffer.get_mut().unwrap(), 5).unwrap();
2350        let map = buffer.map_readable().unwrap();
2351        assert_eq!(&*map, b"fghij");
2352    }
2353
2354    #[test]
2355    fn test_task() {
2356        crate::init().unwrap();
2357
2358        let pad = crate::Pad::builder(crate::PadDirection::Sink)
2359            .name("sink")
2360            .build();
2361        let (sender, receiver) = channel();
2362
2363        let mut i = 0;
2364        let pad_clone = pad.clone();
2365        pad.start_task(move || {
2366            i += 1;
2367            if i == 3 {
2368                sender.send(i).unwrap();
2369                pad_clone.pause_task().unwrap();
2370            }
2371        })
2372        .unwrap();
2373
2374        assert_eq!(receiver.recv().unwrap(), 3);
2375    }
2376
2377    #[test]
2378    fn test_remove_probe_from_probe() {
2379        crate::init().unwrap();
2380
2381        let src_pad = crate::Pad::builder(crate::PadDirection::Src)
2382            .name("src")
2383            .build();
2384        let sink_pad = crate::Pad::builder(crate::PadDirection::Sink)
2385            .name("sink")
2386            .chain_function(|_pad, _parent, _buffer| Ok(crate::FlowSuccess::Ok))
2387            .build();
2388
2389        src_pad.link(&sink_pad).unwrap();
2390
2391        let counter = Arc::new(AtomicUsize::new(0));
2392        let counter_clone = counter.clone();
2393        src_pad.add_probe(crate::PadProbeType::BUFFER, move |pad, info| {
2394            if let Some(PadProbeData::Buffer(_)) = info.data {
2395                counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
2396                pad.remove_probe(info.id.take().expect("no pad probe id"));
2397            } else {
2398                unreachable!();
2399            }
2400            crate::PadProbeReturn::Handled
2401        });
2402
2403        sink_pad.set_active(true).unwrap();
2404        src_pad.set_active(true).unwrap();
2405
2406        assert!(src_pad.push_event(crate::event::StreamStart::new("test")));
2407        let segment = crate::FormattedSegment::<crate::ClockTime>::new();
2408        assert!(src_pad.push_event(crate::event::Segment::new(segment.as_ref())));
2409
2410        assert_eq!(src_pad.push(crate::Buffer::new()), Ok(FlowSuccess::Ok));
2411        assert_eq!(src_pad.push(crate::Buffer::new()), Ok(FlowSuccess::Ok));
2412
2413        assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 1);
2414    }
2415
2416    fn do_probe_with_return(probe_return: crate::PadProbeReturn) {
2417        skip_assert_initialized!();
2418        crate::init().unwrap();
2419
2420        let (major, minor, micro, _) = crate::version();
2421        let pad = crate::Pad::builder(crate::PadDirection::Src)
2422            .name("src")
2423            .build();
2424        let events = Arc::new(Mutex::new(Vec::new()));
2425        let buffers = Arc::new(Mutex::new(Vec::new()));
2426
2427        let flow_override = if (major, minor, micro) >= (1, 16, 1) {
2428            Err(FlowError::Eos)
2429        } else {
2430            // Broken on 1.16.0
2431            // https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/151
2432            Ok(FlowSuccess::Ok)
2433        };
2434
2435        {
2436            let events = events.clone();
2437            pad.add_probe(crate::PadProbeType::EVENT_DOWNSTREAM, move |_, info| {
2438                if let Some(PadProbeData::Event(event)) = &info.data {
2439                    let mut events = events.lock().unwrap();
2440                    events.push(event.clone());
2441                } else {
2442                    unreachable!();
2443                }
2444                crate::PadProbeReturn::Ok
2445            });
2446        }
2447
2448        {
2449            let events = events.clone();
2450            pad.add_probe(crate::PadProbeType::EVENT_UPSTREAM, move |_, info| {
2451                if let Some(event) = info.take_event() {
2452                    let mut events = events.lock().unwrap();
2453                    events.push(event);
2454                } else {
2455                    unreachable!();
2456                }
2457                probe_return
2458            });
2459        }
2460
2461        {
2462            let buffers = buffers.clone();
2463            pad.add_probe(crate::PadProbeType::BUFFER, move |_, info| {
2464                if let Some(buffer) = info.take_buffer() {
2465                    let mut buffers = buffers.lock().unwrap();
2466                    info.flow_res = if buffers.is_empty() {
2467                        Ok(FlowSuccess::Ok)
2468                    } else {
2469                        flow_override
2470                    };
2471                    buffers.push(buffer);
2472                } else {
2473                    unreachable!();
2474                }
2475                probe_return
2476            });
2477        }
2478
2479        pad.set_active(true).unwrap();
2480
2481        assert!(
2482            pad.send_event(crate::event::Latency::new(crate::ClockTime::from_nseconds(
2483                10
2484            )))
2485        );
2486        assert!(pad.push_event(crate::event::StreamStart::new("test")));
2487        let segment = crate::FormattedSegment::<crate::ClockTime>::new();
2488        assert!(pad.push_event(crate::event::Segment::new(segment.as_ref())));
2489
2490        assert_eq!(pad.push(crate::Buffer::new()), Ok(FlowSuccess::Ok));
2491        assert_eq!(
2492            pad.push(crate::Buffer::new()),
2493            // On Drop, we will get an Ok, not whatever value we returned
2494            if probe_return == crate::PadProbeReturn::Drop {
2495                Ok(FlowSuccess::Ok)
2496            } else {
2497                flow_override
2498            }
2499        );
2500
2501        let events = events.lock().unwrap();
2502        let buffers = buffers.lock().unwrap();
2503        assert_eq!(events.len(), 3);
2504        assert_eq!(buffers.len(), 2);
2505
2506        assert_eq!(events[0].type_(), crate::EventType::Latency);
2507        assert_eq!(events[1].type_(), crate::EventType::StreamStart);
2508        assert_eq!(events[2].type_(), crate::EventType::Segment);
2509
2510        assert!(
2511            buffers.iter().all(|b| b.is_writable()),
2512            "A buffer ref leaked!"
2513        );
2514
2515        drop(pad); // Need to drop the pad first to unref sticky events
2516        assert!(
2517            events.iter().all(|e| e.is_writable()),
2518            "An event ref leaked!"
2519        );
2520    }
2521
2522    #[test]
2523    fn test_probe() {
2524        crate::init().unwrap();
2525        do_probe_with_return(crate::PadProbeReturn::Handled);
2526    }
2527
2528    #[test]
2529    fn test_probe_drop() {
2530        crate::init().unwrap();
2531        do_probe_with_return(crate::PadProbeReturn::Drop);
2532    }
2533
2534    #[test]
2535    fn test_sticky_events() {
2536        crate::init().unwrap();
2537
2538        let pad = crate::Pad::builder(crate::PadDirection::Sink)
2539            .name("sink")
2540            .build();
2541        pad.set_active(true).unwrap();
2542
2543        // Send some sticky events
2544        assert!(pad.send_event(crate::event::StreamStart::new("test")));
2545
2546        let caps = crate::Caps::builder("some/x-caps").build();
2547        assert!(pad.send_event(crate::event::Caps::new(&caps)));
2548
2549        let segment = crate::FormattedSegment::<crate::ClockTime>::new();
2550        assert!(pad.send_event(crate::event::Segment::new(segment.as_ref())));
2551
2552        let stream_start = pad.sticky_event::<crate::event::StreamStart>(0).unwrap();
2553        assert_eq!(stream_start.stream_id(), "test");
2554
2555        let caps2 = pad.sticky_event::<crate::event::Caps>(0).unwrap();
2556        assert_eq!(&*caps, caps2.caps());
2557
2558        let segment = pad.sticky_event::<crate::event::Segment>(0).unwrap();
2559        assert_eq!(segment.segment().format(), crate::Format::Time);
2560    }
2561
2562    #[test]
2563    fn test_sticky_events_foreach() {
2564        crate::init().unwrap();
2565
2566        let pad = crate::Pad::builder(crate::PadDirection::Sink)
2567            .name("sink")
2568            .build();
2569        pad.set_active(true).unwrap();
2570
2571        // Send some sticky events
2572        assert!(pad.send_event(crate::event::StreamStart::new("test")));
2573
2574        let caps = crate::Caps::builder("some/x-caps").build();
2575        assert!(pad.send_event(crate::event::Caps::new(&caps)));
2576
2577        let segment = crate::FormattedSegment::<crate::ClockTime>::new();
2578        assert!(pad.send_event(crate::event::Segment::new(segment.as_ref())));
2579
2580        let mut sticky_events = Vec::new();
2581        pad.sticky_events_foreach(|event| {
2582            sticky_events.push(event.clone());
2583            ControlFlow::Continue(EventForeachAction::Keep)
2584        });
2585        assert_eq!(sticky_events.len(), 3);
2586
2587        // Test early exit from foreach loop
2588        let mut sticky_events2 = Vec::new();
2589        pad.sticky_events_foreach(|event| {
2590            sticky_events2.push(event.clone());
2591            if event.type_() == crate::EventType::Caps {
2592                ControlFlow::Break(EventForeachAction::Keep)
2593            } else {
2594                ControlFlow::Continue(EventForeachAction::Keep)
2595            }
2596        });
2597        assert_eq!(sticky_events2.len(), 2);
2598
2599        let mut sticky_events3 = Vec::new();
2600        pad.sticky_events_foreach(|event| {
2601            sticky_events3.push(event.clone());
2602            ControlFlow::Continue(EventForeachAction::Keep)
2603        });
2604        assert_eq!(sticky_events3.len(), 3);
2605
2606        for (e1, e2) in sticky_events.iter().zip(sticky_events3.iter()) {
2607            assert_eq!(e1.as_ref() as *const _, e2.as_ref() as *const _);
2608        }
2609
2610        // Replace segment event
2611        pad.sticky_events_foreach(|event| {
2612            let action = if event.type_() == crate::EventType::Segment {
2613                let byte_segment = crate::FormattedSegment::<crate::format::Bytes>::new();
2614                EventForeachAction::Replace(crate::event::Segment::new(&byte_segment))
2615            } else {
2616                EventForeachAction::Keep
2617            };
2618            ControlFlow::Continue(action)
2619        });
2620
2621        // Check that segment event is different now
2622        let mut sticky_events4 = Vec::new();
2623        pad.sticky_events_foreach(|event| {
2624            sticky_events4.push(event.clone());
2625            ControlFlow::Continue(EventForeachAction::Keep)
2626        });
2627        assert_eq!(sticky_events4.len(), 3);
2628        assert_eq!(
2629            sticky_events[0].as_ref() as *const _,
2630            sticky_events4[0].as_ref() as *const _
2631        );
2632        assert_eq!(
2633            sticky_events[1].as_ref() as *const _,
2634            sticky_events4[1].as_ref() as *const _
2635        );
2636        assert_ne!(
2637            sticky_events[2].as_ref() as *const _,
2638            sticky_events4[2].as_ref() as *const _
2639        );
2640
2641        // Drop caps event
2642        pad.sticky_events_foreach(|event| {
2643            let action = if event.type_() == crate::EventType::Caps {
2644                EventForeachAction::Remove
2645            } else {
2646                EventForeachAction::Keep
2647            };
2648            ControlFlow::Continue(action)
2649        });
2650
2651        // Check that caps event actually got removed
2652        let mut sticky_events5 = Vec::new();
2653        pad.sticky_events_foreach(|event| {
2654            sticky_events5.push(event.clone());
2655            ControlFlow::Continue(EventForeachAction::Keep)
2656        });
2657        assert_eq!(sticky_events5.len(), 2);
2658        assert_eq!(
2659            sticky_events4[0].as_ref() as *const _,
2660            sticky_events5[0].as_ref() as *const _
2661        );
2662        assert_eq!(
2663            sticky_events4[2].as_ref() as *const _,
2664            sticky_events5[1].as_ref() as *const _
2665        );
2666    }
2667
2668    #[test]
2669    #[allow(deprecated)] // maybe_name() is deprecated
2670    fn naming() {
2671        crate::init().unwrap();
2672
2673        let pad = crate::Pad::builder(crate::PadDirection::Sink).build();
2674        assert!(pad.name().starts_with("pad"));
2675
2676        let pad = crate::Pad::builder(crate::PadDirection::Src).build();
2677        assert!(pad.name().starts_with("pad"));
2678
2679        let pad = crate::Pad::builder(crate::PadDirection::Unknown).build();
2680        assert!(pad.name().starts_with("pad"));
2681
2682        let pad = crate::Pad::builder(crate::PadDirection::Unknown)
2683            .generated_name()
2684            .build();
2685        assert!(pad.name().starts_with("pad"));
2686
2687        let pad = crate::Pad::builder(crate::PadDirection::Unknown)
2688            .maybe_name(None::<&str>)
2689            .build();
2690        assert!(pad.name().starts_with("pad"));
2691
2692        let pad = crate::Pad::builder(crate::PadDirection::Unknown)
2693            .name_if_some(None::<&str>)
2694            .build();
2695        assert!(pad.name().starts_with("pad"));
2696
2697        let pad = crate::Pad::builder(crate::PadDirection::Sink)
2698            .name("sink_0")
2699            .build();
2700        assert_eq!(pad.name(), "sink_0");
2701
2702        let pad = crate::Pad::builder(crate::PadDirection::Src)
2703            .name("src_0")
2704            .build();
2705        assert_eq!(pad.name(), "src_0");
2706
2707        let pad = crate::Pad::builder(crate::PadDirection::Unknown)
2708            .name("test")
2709            .build();
2710        assert_eq!(pad.name(), "test");
2711
2712        let pad = crate::Pad::builder(crate::PadDirection::Unknown)
2713            .maybe_name(Some("test"))
2714            .build();
2715        assert_eq!(pad.name(), "test");
2716
2717        let pad = crate::Pad::builder(crate::PadDirection::Unknown)
2718            .name_if_some(Some("test"))
2719            .build();
2720        assert_eq!(pad.name(), "test");
2721
2722        let caps = crate::Caps::new_any();
2723        let templ = crate::PadTemplate::new(
2724            "sink",
2725            crate::PadDirection::Sink,
2726            crate::PadPresence::Always,
2727            &caps,
2728        )
2729        .unwrap();
2730
2731        let pad = Pad::from_template(&templ);
2732        assert!(pad.name().starts_with("sink"));
2733
2734        let pad = Pad::builder_from_template(&templ)
2735            .name("audio_sink")
2736            .build();
2737        assert!(pad.name().starts_with("audio_sink"));
2738
2739        let pad = Pad::builder_from_template(&templ).generated_name().build();
2740        assert!(pad.name().starts_with("pad"));
2741
2742        let templ = crate::PadTemplate::new(
2743            "audio_%u",
2744            crate::PadDirection::Sink,
2745            crate::PadPresence::Request,
2746            &caps,
2747        )
2748        .unwrap();
2749
2750        let pad = Pad::builder_from_template(&templ).name("audio_0").build();
2751        assert!(pad.name().starts_with("audio_0"));
2752
2753        let pad = Pad::builder_from_template(&templ).generated_name().build();
2754        assert!(pad.name().starts_with("pad"));
2755    }
2756
2757    #[test]
2758    #[should_panic]
2759    fn missing_name() {
2760        crate::init().unwrap();
2761
2762        let caps = crate::Caps::new_any();
2763        let templ = crate::PadTemplate::new(
2764            "audio_%u",
2765            crate::PadDirection::Sink,
2766            crate::PadPresence::Request,
2767            &caps,
2768        )
2769        .unwrap();
2770
2771        // Panic: attempt to build from a wildcard-named template
2772        //        without providing a name.
2773        let _pad = Pad::from_template(&templ);
2774    }
2775}