gstreamer/
pad.rs

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