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