1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::translate::*;
4
5use crate::{
6 prelude::*, FlowError, FlowSuccess, GhostPad, LoggableError, Pad, PadBuilder, PadFlags,
7 PadGetRangeSuccess, PadMode, StaticPadTemplate,
8};
9
10impl GhostPad {
11 #[doc(alias = "gst_ghost_pad_activate_mode_default")]
12 pub fn activate_mode_default<P: IsA<GhostPad>>(
13 pad: &P,
14 parent: Option<&impl IsA<crate::Object>>,
15 mode: PadMode,
16 active: bool,
17 ) -> Result<(), glib::BoolError> {
18 skip_assert_initialized!();
19 unsafe {
20 glib::result_from_gboolean!(
21 ffi::gst_ghost_pad_activate_mode_default(
22 pad.to_glib_none().0 as *mut ffi::GstPad,
23 parent.map(|p| p.as_ref()).to_glib_none().0,
24 mode.into_glib(),
25 active.into_glib(),
26 ),
27 "Failed to invoke the default activate mode function of the ghost pad"
28 )
29 }
30 }
31
32 #[doc(alias = "gst_ghost_pad_internal_activate_mode_default")]
33 pub fn internal_activate_mode_default<P: IsA<GhostPad>>(
34 pad: &P,
35 parent: Option<&impl IsA<crate::Object>>,
36 mode: PadMode,
37 active: bool,
38 ) -> Result<(), glib::BoolError> {
39 skip_assert_initialized!();
40 unsafe {
41 glib::result_from_gboolean!(
42 ffi::gst_ghost_pad_internal_activate_mode_default(
43 pad.to_glib_none().0 as *mut ffi::GstPad,
44 parent.map(|p| p.as_ref()).to_glib_none().0,
45 mode.into_glib(),
46 active.into_glib(),
47 ),
48 concat!(
49 "Failed to invoke the default activate mode function of a proxy pad ",
50 "that is owned by the ghost pad"
51 )
52 )
53 }
54 }
55
56 // rustdoc-stripper-ignore-next
57 /// Creates a new [`GhostPad`] with an automatically generated name.
58 ///
59 /// Use [`GhostPad::builder_from_template()`] to get a [`PadBuilder`](crate::PadBuilder)
60 /// and define options.
61 #[doc(alias = "gst_ghost_pad_new_no_target")]
62 pub fn new(direction: crate::PadDirection) -> Self {
63 skip_assert_initialized!();
64 Self::builder(direction).build()
65 }
66
67 // rustdoc-stripper-ignore-next
68 /// Creates a [`PadBuilder`](crate::PadBuilder) for a [`PadBuilder`] with an automatically generated name.
69 ///
70 /// Use [`PadBuilder::name`](crate::PadBuilder::name) or [`PadBuilder::maybe_name`](crate::PadBuilder::maybe_name)
71 /// to specify a different name.
72 #[doc(alias = "gst_ghost_pad_new_no_target")]
73 pub fn builder(direction: crate::PadDirection) -> PadBuilder<Self> {
74 skip_assert_initialized!();
75 PadBuilder::new(direction)
76 }
77
78 // rustdoc-stripper-ignore-next
79 /// Creates a new [`GhostPad`] from the [`StaticPadTemplate`](crate::StaticPadTemplate).
80 ///
81 /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`,
82 /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
83 /// the `GhostPad` will automatically be named after the `name_template`.
84 ///
85 /// # Panics
86 ///
87 /// Panics if the `name_template` is a wildcard-name.
88 ///
89 /// Use [`GhostPad::builder_from_template()`] to get a [`PadBuilder`](crate::PadBuilder)
90 /// and define options.
91 #[doc(alias = "gst_ghost_pad_new_no_target_from_static_template")]
92 pub fn from_static_template(templ: &StaticPadTemplate) -> Self {
93 skip_assert_initialized!();
94 Self::builder_from_static_template(templ).build()
95 }
96
97 // rustdoc-stripper-ignore-next
98 /// Creates a new [`PadBuilder`](crate::PadBuilder) for a [`GhostPad`] from the [`StaticPadTemplate`](crate::StaticPadTemplate).
99 ///
100 /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`,
101 /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
102 /// the `GhostPad` will automatically be named after the `name_template`.
103 ///
104 /// Use [`PadBuilder::name`](crate::PadBuilder::name) or [`PadBuilder::maybe_name`](crate::PadBuilder::maybe_name)
105 /// to specify a different name.
106 #[doc(alias = "gst_ghost_pad_new_no_target_from_static_template")]
107 pub fn builder_from_static_template(templ: &StaticPadTemplate) -> PadBuilder<Self> {
108 skip_assert_initialized!();
109 PadBuilder::from_static_template(templ)
110 }
111
112 // rustdoc-stripper-ignore-next
113 /// Creates a new [`GhostPad`] from the [`PadTemplate`](crate::PadTemplate).
114 ///
115 /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`,
116 /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
117 /// the `GhostPad` will automatically be named after the `name_template`.
118 ///
119 /// # Panics
120 ///
121 /// Panics if the `name_template` is a wildcard-name.
122 ///
123 /// Use [`GhostPad::builder_from_template()`] to get a [`PadBuilder`](crate::PadBuilder)
124 /// and define options.
125 #[doc(alias = "gst_ghost_pad_new_no_target_from_template")]
126 pub fn from_template(templ: &crate::PadTemplate) -> Self {
127 skip_assert_initialized!();
128 Self::builder_from_template(templ).build()
129 }
130
131 // rustdoc-stripper-ignore-next
132 /// Creates a new [`PadBuilder`](crate::PadBuilder) for a [`GhostPad`] from the [`PadTemplate`](crate::PadTemplate).
133 ///
134 /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`,
135 /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
136 /// the `GhostPad` will automatically be named after the `name_template`.
137 ///
138 /// Use [`PadBuilder::name`](crate::PadBuilder::name) or [`PadBuilder::maybe_name`](crate::PadBuilder::maybe_name)
139 /// to specify a different name.
140 #[doc(alias = "gst_ghost_pad_new_no_target_from_template")]
141 pub fn builder_from_template(templ: &crate::PadTemplate) -> PadBuilder<Self> {
142 skip_assert_initialized!();
143 PadBuilder::from_template(templ)
144 }
145
146 // rustdoc-stripper-ignore-next
147 /// Creates a new [`GhostPad`] from the specified `target` `Pad`.
148 ///
149 /// The `GhostPad` will automatically be named after the `target` `name`.
150 ///
151 /// Use [`GhostPad::builder_with_target()`] to get a [`PadBuilder`](crate::PadBuilder)
152 /// and define options.
153 #[doc(alias = "gst_ghost_pad_new")]
154 pub fn with_target<P: IsA<Pad> + IsA<crate::Object>>(
155 target: &P,
156 ) -> Result<Self, glib::BoolError> {
157 skip_assert_initialized!();
158 Ok(Self::builder_with_target(target)?.build())
159 }
160
161 // rustdoc-stripper-ignore-next
162 /// Creates a new [`PadBuilder`](crate::PadBuilder) for a [`GhostPad`] from the specified `target` `Pad`.
163 ///
164 /// The `GhostPad` will automatically be named after the `target` `name`.
165 ///
166 /// Use [`PadBuilder::name`](crate::PadBuilder::name) or [`PadBuilder::maybe_name`](crate::PadBuilder::maybe_name)
167 /// to specify a different name.
168 #[doc(alias = "gst_ghost_pad_new_no_target_from_template")]
169 pub fn builder_with_target<P: IsA<Pad> + IsA<crate::Object>>(
170 target: &P,
171 ) -> Result<PadBuilder<Self>, glib::BoolError> {
172 skip_assert_initialized!();
173 let mut builder = Self::builder(target.direction());
174 builder.needs_specific_name = true;
175 builder.with_target(target)
176 }
177
178 // rustdoc-stripper-ignore-next
179 /// Creates a new [`GhostPad`] from the [`PadTemplate`](crate::PadTemplate)
180 /// with the specified `target` `Pad`.
181 ///
182 /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`,
183 /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
184 /// the `GhostPad` will automatically be named after the `name_template`.
185 ///
186 /// If the `name_template` is a wildcard-name, then the `target` `name` is used,
187 /// if it is compatible. Otherwise, a specific name must be provided using
188 /// [`PadBuilder::name`](crate::PadBuilder::name) or [`PadBuilder::maybe_name`](crate::PadBuilder::maybe_name).
189 #[doc(alias = "gst_ghost_pad_new_from_template")]
190 pub fn from_template_with_target<P: IsA<Pad> + IsA<crate::Object>>(
191 templ: &crate::PadTemplate,
192 target: &P,
193 ) -> Result<Self, glib::BoolError> {
194 skip_assert_initialized!();
195 Ok(Self::builder_from_template_with_target(templ, target)?.build())
196 }
197
198 // rustdoc-stripper-ignore-next
199 /// Creates a new [`PadBuilder`](crate::PadBuilder) for a [`GhostPad`] from the [`PadTemplate`](crate::PadTemplate)
200 /// with the specified `target` `Pad`.
201 ///
202 /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`,
203 /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
204 /// the `GhostPad` will automatically be named after the `name_template`.
205 ///
206 /// If the `name_template` is a wildcard-name, then the `target` `name` is used,
207 /// if it is compatible. Otherwise, a specific name must be provided using
208 /// [`PadBuilder::name`](crate::PadBuilder::name) or [`PadBuilder::maybe_name`](crate::PadBuilder::maybe_name).
209 #[doc(alias = "gst_ghost_pad_new_from_template")]
210 pub fn builder_from_template_with_target<P: IsA<Pad> + IsA<crate::Object>>(
211 templ: &crate::PadTemplate,
212 target: &P,
213 ) -> Result<PadBuilder<Self>, glib::BoolError> {
214 skip_assert_initialized!();
215
216 if target.direction() != templ.direction() {
217 return Err(glib::bool_error!(
218 "Template and target have different directions"
219 ));
220 }
221
222 Self::builder_from_template(templ).with_target(target)
223 }
224}
225
226impl<T: IsA<GhostPad> + IsA<Pad>> PadBuilder<T> {
227 #[doc(alias = "gst_pad_set_activate_function")]
228 pub fn proxy_pad_activate_function<F>(self, func: F) -> Self
229 where
230 F: Fn(&crate::ProxyPad, Option<&crate::Object>) -> Result<(), LoggableError>
231 + Send
232 + Sync
233 + 'static,
234 {
235 unsafe {
236 let proxy = self
237 .pad
238 .unsafe_cast_ref::<crate::ProxyPad>()
239 .internal()
240 .unwrap();
241 proxy.set_activate_function(func);
242 }
243
244 self
245 }
246
247 #[doc(alias = "gst_pad_set_activatemode_function")]
248 pub fn proxy_pad_activatemode_function<F>(self, func: F) -> Self
249 where
250 F: Fn(
251 &crate::ProxyPad,
252 Option<&crate::Object>,
253 crate::PadMode,
254 bool,
255 ) -> Result<(), LoggableError>
256 + Send
257 + Sync
258 + 'static,
259 {
260 unsafe {
261 let proxy = self
262 .pad
263 .unsafe_cast_ref::<crate::ProxyPad>()
264 .internal()
265 .unwrap();
266 proxy.set_activatemode_function(func);
267 }
268
269 self
270 }
271
272 #[doc(alias = "gst_pad_set_chain_function")]
273 pub fn proxy_pad_chain_function<F>(self, func: F) -> Self
274 where
275 F: Fn(
276 &crate::ProxyPad,
277 Option<&crate::Object>,
278 crate::Buffer,
279 ) -> Result<FlowSuccess, FlowError>
280 + Send
281 + Sync
282 + 'static,
283 {
284 unsafe {
285 let proxy = self
286 .pad
287 .unsafe_cast_ref::<crate::ProxyPad>()
288 .internal()
289 .unwrap();
290 proxy.set_chain_function(func);
291 }
292
293 self
294 }
295
296 #[doc(alias = "gst_pad_set_chain_list_function")]
297 pub fn proxy_pad_chain_list_function<F>(self, func: F) -> Self
298 where
299 F: Fn(
300 &crate::ProxyPad,
301 Option<&crate::Object>,
302 crate::BufferList,
303 ) -> Result<FlowSuccess, FlowError>
304 + Send
305 + Sync
306 + 'static,
307 {
308 unsafe {
309 let proxy = self
310 .pad
311 .unsafe_cast_ref::<crate::ProxyPad>()
312 .internal()
313 .unwrap();
314 proxy.set_chain_list_function(func);
315 }
316
317 self
318 }
319
320 #[doc(alias = "gst_pad_set_event_function")]
321 pub fn proxy_pad_event_function<F>(self, func: F) -> Self
322 where
323 F: Fn(&crate::ProxyPad, Option<&crate::Object>, crate::Event) -> bool
324 + Send
325 + Sync
326 + 'static,
327 {
328 unsafe {
329 let proxy = self
330 .pad
331 .unsafe_cast_ref::<crate::ProxyPad>()
332 .internal()
333 .unwrap();
334 proxy.set_event_function(func);
335 }
336
337 self
338 }
339
340 #[doc(alias = "gst_pad_set_event_full_function")]
341 pub fn proxy_pad_event_full_function<F>(self, func: F) -> Self
342 where
343 F: Fn(
344 &crate::ProxyPad,
345 Option<&crate::Object>,
346 crate::Event,
347 ) -> Result<FlowSuccess, FlowError>
348 + Send
349 + Sync
350 + 'static,
351 {
352 unsafe {
353 let proxy = self
354 .pad
355 .unsafe_cast_ref::<crate::ProxyPad>()
356 .internal()
357 .unwrap();
358 proxy.set_event_full_function(func);
359 }
360
361 self
362 }
363
364 #[doc(alias = "gst_pad_set_getrange_function")]
365 pub fn proxy_pad_getrange_function<F>(self, func: F) -> Self
366 where
367 F: Fn(
368 &crate::ProxyPad,
369 Option<&crate::Object>,
370 u64,
371 Option<&mut crate::BufferRef>,
372 u32,
373 ) -> Result<PadGetRangeSuccess, crate::FlowError>
374 + Send
375 + Sync
376 + 'static,
377 {
378 unsafe {
379 let proxy = self
380 .pad
381 .unsafe_cast_ref::<crate::ProxyPad>()
382 .internal()
383 .unwrap();
384 proxy.set_getrange_function(func);
385 }
386
387 self
388 }
389
390 #[doc(alias = "gst_pad_set_iterate_internal_links_function")]
391 pub fn proxy_pad_iterate_internal_links_function<F>(self, func: F) -> Self
392 where
393 F: Fn(&crate::ProxyPad, Option<&crate::Object>) -> crate::Iterator<Pad>
394 + Send
395 + Sync
396 + 'static,
397 {
398 unsafe {
399 let proxy = self
400 .pad
401 .unsafe_cast_ref::<crate::ProxyPad>()
402 .internal()
403 .unwrap();
404 proxy.set_iterate_internal_links_function(func);
405 }
406
407 self
408 }
409
410 #[doc(alias = "gst_pad_set_link_function")]
411 pub fn proxy_pad_link_function<F>(self, func: F) -> Self
412 where
413 F: Fn(
414 &crate::ProxyPad,
415 Option<&crate::Object>,
416 &Pad,
417 ) -> Result<crate::PadLinkSuccess, crate::PadLinkError>
418 + Send
419 + Sync
420 + 'static,
421 {
422 unsafe {
423 let proxy = self
424 .pad
425 .unsafe_cast_ref::<crate::ProxyPad>()
426 .internal()
427 .unwrap();
428 proxy.set_link_function(func);
429 }
430
431 self
432 }
433
434 #[doc(alias = "gst_pad_set_query_function")]
435 pub fn proxy_pad_query_function<F>(self, func: F) -> Self
436 where
437 F: Fn(&crate::ProxyPad, Option<&crate::Object>, &mut crate::QueryRef) -> bool
438 + Send
439 + Sync
440 + 'static,
441 {
442 unsafe {
443 let proxy = self
444 .pad
445 .unsafe_cast_ref::<crate::ProxyPad>()
446 .internal()
447 .unwrap();
448 proxy.set_query_function(func);
449 }
450
451 self
452 }
453
454 #[doc(alias = "gst_pad_set_unlink_function")]
455 pub fn proxy_pad_unlink_function<F>(self, func: F) -> Self
456 where
457 F: Fn(&crate::ProxyPad, Option<&crate::Object>) + Send + Sync + 'static,
458 {
459 unsafe {
460 let proxy = self
461 .pad
462 .unsafe_cast_ref::<crate::ProxyPad>()
463 .internal()
464 .unwrap();
465 proxy.set_unlink_function(func);
466 }
467
468 self
469 }
470
471 pub fn proxy_pad_flags(self, flags: PadFlags) -> Self {
472 unsafe {
473 let proxy = self
474 .pad
475 .unsafe_cast_ref::<crate::ProxyPad>()
476 .internal()
477 .unwrap();
478 proxy.set_pad_flags(flags);
479 }
480
481 self
482 }
483
484 // rustdoc-stripper-ignore-next
485 /// Specifies a `target` [`Pad`](crate::Pad) for the [`GhostPad`].
486 ///
487 /// If the [`PadBuilder`](crate::PadBuilder) was created from
488 /// a [`PadTemplate`](crate::PadTemplate) and the `PadTemplate` has a specific `name_template`,
489 /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
490 /// the `GhostPad` will automatically be named after the `name_template`.
491 ///
492 /// If the `name_template` is a wildcard-name, then the `target` `name` is used,
493 /// if it is compatible. Otherwise, a specific name must be provided using
494 /// [`PadBuilder::name`](crate::PadBuilder::name) or [`PadBuilder::maybe_name`](crate::PadBuilder::maybe_name).
495 pub fn with_target<P: IsA<Pad> + IsA<crate::Object>>(
496 mut self,
497 target: &P,
498 ) -> Result<Self, glib::BoolError> {
499 assert_eq!(self.pad.direction(), target.direction());
500
501 self.pad.set_target(Some(target))?;
502
503 if self.needs_specific_name {
504 let mut can_assign_target_name = true;
505
506 if let Some(pad_template) = self.pad.pad_template() {
507 if pad_template.presence() == crate::PadPresence::Request {
508 // Check if the target name is compatible with the name template.
509 use crate::CAT_RUST;
510
511 let target_name = target.name();
512 let mut target_parts = target_name.split('_');
513 for template_part in pad_template.name_template().split('_') {
514 let Some(target_part) = target_parts.next() else {
515 crate::debug!(
516 CAT_RUST,
517 "Not using target Pad name '{target_name}': not enough parts compared to template '{}'",
518 pad_template.name_template(),
519 );
520 can_assign_target_name = false;
521 break;
522 };
523
524 if let Some(conv_spec_start) = template_part.find('%') {
525 if conv_spec_start > 0
526 && !target_part.starts_with(&template_part[..conv_spec_start])
527 {
528 crate::debug!(
529 CAT_RUST,
530 "Not using target Pad name '{target_name}': mismatch template '{}' prefix",
531 pad_template.name_template(),
532 );
533 can_assign_target_name = false;
534 break;
535 }
536
537 let conv_spec_pos = conv_spec_start + 1;
538 match template_part.get(conv_spec_pos..=conv_spec_pos) {
539 Some("s") => {
540 // *There can be only one* %s
541 break;
542 }
543 Some("u") => {
544 if target_part
545 .get(conv_spec_start..)
546 .map_or(true, |s| s.parse::<u32>().is_err())
547 {
548 crate::debug!(
549 CAT_RUST,
550 "Not using target Pad name '{target_name}': can't parse '%u' from '{target_part}' (template '{}')",
551 pad_template.name_template(),
552 );
553
554 can_assign_target_name = false;
555 break;
556 }
557 }
558 Some("d") => {
559 if target_part
560 .get(conv_spec_start..)
561 .map_or(true, |s| s.parse::<i32>().is_err())
562 {
563 crate::debug!(
564 CAT_RUST,
565 "Not using target Pad name '{target_name}': can't parse '%i' from '{target_part}' (template '{}')",
566 pad_template.name_template(),
567 );
568
569 can_assign_target_name = false;
570 break;
571 }
572 }
573 other => unreachable!("Unexpected conversion specifier {other:?}"),
574 }
575 } else if target_part != template_part {
576 can_assign_target_name = false;
577 break;
578 }
579 }
580 }
581 }
582
583 if can_assign_target_name {
584 self.pad.set_property("name", target.name());
585 self.needs_specific_name = false;
586 }
587 }
588
589 Ok(self)
590 }
591}
592
593#[cfg(test)]
594mod tests {
595 use super::*;
596
597 #[test]
598 fn no_template_no_target() {
599 crate::init().unwrap();
600
601 let ghost_pad = GhostPad::new(crate::PadDirection::Sink);
602 assert!(ghost_pad.name().starts_with("ghostpad"));
603
604 let ghost_pad = GhostPad::builder(crate::PadDirection::Sink).build();
605 assert!(ghost_pad.name().starts_with("ghostpad"));
606
607 let ghost_pad = GhostPad::builder(crate::PadDirection::Sink)
608 .name("sink")
609 .build();
610 assert_eq!(ghost_pad.name(), "sink");
611 }
612
613 #[test]
614 fn from_template() {
615 crate::init().unwrap();
616
617 let caps = crate::Caps::new_any();
618 let wildcard_templ = crate::PadTemplate::new(
619 "sink_%u",
620 crate::PadDirection::Sink,
621 crate::PadPresence::Request,
622 &caps,
623 )
624 .unwrap();
625
626 let ghost_pad = GhostPad::builder_from_template(&wildcard_templ)
627 .name("my-ghostpad")
628 .build();
629 assert_eq!(ghost_pad.name(), "my-ghostpad");
630
631 let caps = crate::Caps::new_any();
632 let templ = crate::PadTemplate::new(
633 "sink",
634 crate::PadDirection::Sink,
635 crate::PadPresence::Always,
636 &caps,
637 )
638 .unwrap();
639
640 let ghost_pad = GhostPad::from_template(&templ);
641 assert_eq!(ghost_pad.name(), "sink");
642
643 let ghost_pad = GhostPad::builder_from_template(&templ).build();
644 assert!(ghost_pad.name().starts_with("sink"));
645
646 let ghost_pad = GhostPad::builder_from_template(&templ)
647 .name("my-sink")
648 .build();
649 assert_eq!(ghost_pad.name(), "my-sink");
650 }
651
652 #[test]
653 #[should_panic]
654 fn from_template_missing_name() {
655 crate::init().unwrap();
656
657 let caps = crate::Caps::new_any();
658 let templ = crate::PadTemplate::new(
659 "audio_%u",
660 crate::PadDirection::Sink,
661 crate::PadPresence::Request,
662 &caps,
663 )
664 .unwrap();
665
666 // Panic: attempt to build from a wildcard-named template
667 // without providing a name.
668 let _ghost_pad = GhostPad::from_template(&templ);
669 }
670
671 #[test]
672 #[should_panic]
673 fn from_template_builder_missing_name() {
674 crate::init().unwrap();
675
676 let caps = crate::Caps::new_any();
677 let templ = crate::PadTemplate::new(
678 "audio_%u",
679 crate::PadDirection::Sink,
680 crate::PadPresence::Request,
681 &caps,
682 )
683 .unwrap();
684
685 // Panic: attempt to build from a wildcard-named template
686 // without providing a name.
687 let _ghost_pad = GhostPad::builder_from_template(&templ).build();
688 }
689
690 #[test]
691 fn with_target() {
692 crate::init().unwrap();
693
694 let caps = crate::Caps::new_any();
695 let templ = crate::PadTemplate::new(
696 "test",
697 crate::PadDirection::Sink,
698 crate::PadPresence::Always,
699 &caps,
700 )
701 .unwrap();
702
703 let target = crate::Pad::builder_from_template(&templ).build();
704 let ghost_pad = GhostPad::with_target(&target).unwrap();
705 assert_eq!(ghost_pad.name(), "test");
706
707 let target = crate::Pad::from_template(&templ);
708 let ghost_pad = GhostPad::builder_with_target(&target).unwrap().build();
709 assert_eq!(ghost_pad.name(), "test");
710
711 let target = crate::Pad::from_template(&templ);
712 let ghost_pad = GhostPad::builder_with_target(&target)
713 .unwrap()
714 .name("ghost_test")
715 .build();
716 assert_eq!(ghost_pad.name(), "ghost_test");
717 }
718
719 #[test]
720 fn from_template_with_target() {
721 crate::init().unwrap();
722
723 let caps = crate::Caps::new_any();
724 let sink_templ = crate::PadTemplate::new(
725 "sink",
726 crate::PadDirection::Sink,
727 crate::PadPresence::Always,
728 &caps,
729 )
730 .unwrap();
731
732 // # No conversion specifier, Always template
733 let ghost_templ = crate::PadTemplate::new(
734 "ghost_sink",
735 crate::PadDirection::Sink,
736 crate::PadPresence::Always,
737 &caps,
738 )
739 .unwrap();
740
741 let target = crate::Pad::from_template(&sink_templ);
742 let ghost_pad = GhostPad::from_template_with_target(&ghost_templ, &target).unwrap();
743 assert_eq!(ghost_pad.name(), "ghost_sink");
744
745 let target = crate::Pad::from_template(&sink_templ);
746 let ghost_pad = GhostPad::builder_from_template_with_target(&ghost_templ, &target)
747 .unwrap()
748 .build();
749 assert_eq!(ghost_pad.name(), "ghost_sink");
750
751 let target = crate::Pad::from_template(&sink_templ);
752 let ghost_pad = GhostPad::builder_from_template_with_target(&ghost_templ, &target)
753 .unwrap()
754 .name("my-sink")
755 .build();
756 assert_eq!(ghost_pad.name(), "my-sink");
757
758 // # Request template %u
759 let wildcard_u_templ = crate::PadTemplate::new(
760 "sink_%u",
761 crate::PadDirection::Sink,
762 crate::PadPresence::Request,
763 &caps,
764 )
765 .unwrap();
766
767 // ## Incompatible target but specific name
768 let target = crate::Pad::from_template(&sink_templ);
769 let ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_u_templ, &target)
770 .unwrap()
771 .name("sink_0")
772 .build();
773 assert_eq!(ghost_pad.name(), "sink_0");
774
775 // ## Compatible target
776 let sink_0_templ = crate::PadTemplate::new(
777 "sink_0",
778 crate::PadDirection::Sink,
779 crate::PadPresence::Always,
780 &caps,
781 )
782 .unwrap();
783 let target = crate::Pad::from_template(&sink_0_templ);
784 let ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_u_templ, &target)
785 .unwrap()
786 .build();
787 assert_eq!(ghost_pad.name(), "sink_0");
788
789 // # Request template %d_%u
790 let wildcard_u_templ = crate::PadTemplate::new(
791 "sink_%d_%u",
792 crate::PadDirection::Sink,
793 crate::PadPresence::Request,
794 &caps,
795 )
796 .unwrap();
797
798 // ## Incompatible target but specific name
799 let target = crate::Pad::from_template(&sink_templ);
800 let ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_u_templ, &target)
801 .unwrap()
802 .name("sink_-1_0")
803 .build();
804 assert_eq!(ghost_pad.name(), "sink_-1_0");
805
806 // ## Compatible target
807 let sink_m2_0_templ = crate::PadTemplate::new(
808 "sink_-2_0",
809 crate::PadDirection::Sink,
810 crate::PadPresence::Always,
811 &caps,
812 )
813 .unwrap();
814 let target = crate::Pad::from_template(&sink_m2_0_templ);
815 let ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_u_templ, &target)
816 .unwrap()
817 .build();
818 assert_eq!(ghost_pad.name(), "sink_-2_0");
819
820 // # Request template %s
821 let wildcard_s_templ = crate::PadTemplate::new(
822 "sink_%s",
823 crate::PadDirection::Sink,
824 crate::PadPresence::Request,
825 &caps,
826 )
827 .unwrap();
828
829 // ## Incompatible target but specific name
830 let target = crate::Pad::from_template(&sink_templ);
831 let ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_s_templ, &target)
832 .unwrap()
833 .name("sink_ghost_test")
834 .build();
835 assert_eq!(ghost_pad.name(), "sink_ghost_test");
836
837 // ## Compatible target
838 let sink_test_templ = crate::PadTemplate::new(
839 "sink_test",
840 crate::PadDirection::Sink,
841 crate::PadPresence::Always,
842 &caps,
843 )
844 .unwrap();
845 let target = crate::Pad::from_template(&sink_test_templ);
846 let ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_s_templ, &target)
847 .unwrap()
848 .build();
849 assert_eq!(ghost_pad.name(), "sink_test");
850 }
851
852 #[test]
853 #[should_panic]
854 fn from_template_with_target_incompatible_prefix() {
855 crate::init().unwrap();
856
857 let caps = crate::Caps::new_any();
858 let wildcard_templ = crate::PadTemplate::new(
859 "sink_%u",
860 crate::PadDirection::Sink,
861 crate::PadPresence::Request,
862 &caps,
863 )
864 .unwrap();
865
866 let templ = crate::PadTemplate::new(
867 "audio_0",
868 crate::PadDirection::Sink,
869 crate::PadPresence::Always,
870 &caps,
871 )
872 .unwrap();
873
874 let target = crate::Pad::from_template(&templ);
875 // Panic: attempt to build from a wildcard-named template
876 // with a target name with a different prefix
877 // without providing a name.
878 let _ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_templ, &target)
879 .unwrap()
880 .build();
881 }
882
883 #[test]
884 #[should_panic]
885 fn from_template_with_target_missing_part() {
886 crate::init().unwrap();
887
888 let caps = crate::Caps::new_any();
889 let wildcard_templ = crate::PadTemplate::new(
890 "sink_%u_%s",
891 crate::PadDirection::Sink,
892 crate::PadPresence::Request,
893 &caps,
894 )
895 .unwrap();
896
897 let templ = crate::PadTemplate::new(
898 "sink_0",
899 crate::PadDirection::Sink,
900 crate::PadPresence::Always,
901 &caps,
902 )
903 .unwrap();
904
905 let target = crate::Pad::from_template(&templ);
906 // Panic: attempt to build from a wildcard-named template
907 // with a target name missing a part
908 // without providing a name.
909 let _ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_templ, &target)
910 .unwrap()
911 .build();
912 }
913
914 #[test]
915 #[should_panic]
916 fn from_template_with_target_incompatible_conversion_unsigned() {
917 crate::init().unwrap();
918
919 let caps = crate::Caps::new_any();
920 let wildcard_templ = crate::PadTemplate::new(
921 "sink_%u",
922 crate::PadDirection::Sink,
923 crate::PadPresence::Request,
924 &caps,
925 )
926 .unwrap();
927
928 let templ = crate::PadTemplate::new(
929 "sink_-1",
930 crate::PadDirection::Sink,
931 crate::PadPresence::Always,
932 &caps,
933 )
934 .unwrap();
935
936 let target = crate::Pad::from_template(&templ);
937 // Panic: attempt to build from a wildcard-named template
938 // with a target name %d, expecting %u
939 // without providing a name.
940 let _ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_templ, &target)
941 .unwrap()
942 .build();
943 }
944
945 #[test]
946 #[should_panic]
947 fn from_template_with_target_incompatible_conversion_decimal() {
948 crate::init().unwrap();
949
950 let caps = crate::Caps::new_any();
951 let wildcard_templ = crate::PadTemplate::new(
952 "sink_%u",
953 crate::PadDirection::Sink,
954 crate::PadPresence::Request,
955 &caps,
956 )
957 .unwrap();
958
959 let templ = crate::PadTemplate::new(
960 "sink_test",
961 crate::PadDirection::Sink,
962 crate::PadPresence::Always,
963 &caps,
964 )
965 .unwrap();
966
967 let target = crate::Pad::from_template(&templ);
968 // Panic: attempt to build from a wildcard-named template
969 // with a target name with %s, expecting %d
970 // without providing a name.
971 let _ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_templ, &target)
972 .unwrap()
973 .build();
974 }
975
976 #[test]
977 #[should_panic]
978 fn from_template_with_target_incompatible_missing_decimal() {
979 crate::init().unwrap();
980
981 let caps = crate::Caps::new_any();
982 let wildcard_templ = crate::PadTemplate::new(
983 "sink_%d",
984 crate::PadDirection::Sink,
985 crate::PadPresence::Request,
986 &caps,
987 )
988 .unwrap();
989
990 let templ = crate::PadTemplate::new(
991 "sink_",
992 crate::PadDirection::Sink,
993 crate::PadPresence::Always,
994 &caps,
995 )
996 .unwrap();
997
998 let target = crate::Pad::from_template(&templ);
999 // Panic: attempt to build from a wildcard-named template
1000 // with a target name missing a number, expecting %d
1001 // without providing a name.
1002 let _ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_templ, &target)
1003 .unwrap()
1004 .build();
1005 }
1006}
1007