1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use glib::{prelude::*, subclass::prelude::*, translate::*}; |
4 | |
5 | use super::prelude::*; |
6 | use crate::Pad; |
7 | |
8 | pub trait PadImpl: PadImplExt + GstObjectImpl + Send + Sync { |
9 | fn linked(&self, peer: &Pad) { |
10 | self.parent_linked(peer) |
11 | } |
12 | |
13 | fn unlinked(&self, peer: &Pad) { |
14 | self.parent_unlinked(peer) |
15 | } |
16 | } |
17 | |
18 | mod sealed { |
19 | pub trait Sealed {} |
20 | impl<T: super::PadImplExt> Sealed for T {} |
21 | } |
22 | |
23 | pub trait PadImplExt: sealed::Sealed + ObjectSubclass { |
24 | fn parent_linked(&self, peer: &Pad) { |
25 | unsafe { |
26 | let data = Self::type_data(); |
27 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstPadClass; |
28 | |
29 | (*parent_class) |
30 | .linked |
31 | .map(|f| { |
32 | f( |
33 | self.obj().unsafe_cast_ref::<Pad>().to_glib_none().0, |
34 | peer.to_glib_none().0, |
35 | ) |
36 | }) |
37 | .unwrap_or(()) |
38 | } |
39 | } |
40 | |
41 | fn parent_unlinked(&self, peer: &Pad) { |
42 | unsafe { |
43 | let data = Self::type_data(); |
44 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstPadClass; |
45 | |
46 | (*parent_class) |
47 | .unlinked |
48 | .map(|f| { |
49 | f( |
50 | self.obj().unsafe_cast_ref::<Pad>().to_glib_none().0, |
51 | peer.to_glib_none().0, |
52 | ) |
53 | }) |
54 | .unwrap_or(()) |
55 | } |
56 | } |
57 | } |
58 | |
59 | impl<T: PadImpl> PadImplExt for T {} |
60 | |
61 | unsafe impl<T: PadImpl> IsSubclassable<T> for Pad { |
62 | fn class_init(klass: &mut glib::Class<Self>) { |
63 | Self::parent_class_init::<T>(class:klass); |
64 | let klass: &mut GstPadClass = klass.as_mut(); |
65 | klass.linked = Some(pad_linked::<T>); |
66 | klass.unlinked = Some(pad_unlinked::<T>); |
67 | } |
68 | } |
69 | |
70 | unsafe extern "C" fn pad_linked<T: PadImpl>(ptr: *mut ffi::GstPad, peer: *mut ffi::GstPad) { |
71 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
72 | let imp: &T = instance.imp(); |
73 | |
74 | imp.linked(&from_glib_borrow(ptr:peer)) |
75 | } |
76 | |
77 | unsafe extern "C" fn pad_unlinked<T: PadImpl>(ptr: *mut ffi::GstPad, peer: *mut ffi::GstPad) { |
78 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
79 | let imp: &T = instance.imp(); |
80 | |
81 | imp.unlinked(&from_glib_borrow(ptr:peer)) |
82 | } |
83 | |
84 | #[cfg (test)] |
85 | mod tests { |
86 | use std::sync::atomic; |
87 | |
88 | use super::*; |
89 | use crate::{prelude::*, PadDirection}; |
90 | |
91 | pub mod imp { |
92 | use super::*; |
93 | |
94 | #[derive (Default)] |
95 | pub struct TestPad { |
96 | pub(super) linked: atomic::AtomicBool, |
97 | pub(super) unlinked: atomic::AtomicBool, |
98 | } |
99 | |
100 | #[glib::object_subclass ] |
101 | impl ObjectSubclass for TestPad { |
102 | const NAME: &'static str = "TestPad" ; |
103 | type Type = super::TestPad; |
104 | type ParentType = Pad; |
105 | } |
106 | |
107 | impl ObjectImpl for TestPad {} |
108 | |
109 | impl GstObjectImpl for TestPad {} |
110 | |
111 | impl PadImpl for TestPad { |
112 | fn linked(&self, peer: &Pad) { |
113 | self.linked.store(true, atomic::Ordering::SeqCst); |
114 | self.parent_linked(peer) |
115 | } |
116 | |
117 | fn unlinked(&self, peer: &Pad) { |
118 | self.unlinked.store(true, atomic::Ordering::SeqCst); |
119 | self.parent_unlinked(peer) |
120 | } |
121 | } |
122 | } |
123 | |
124 | glib::wrapper! { |
125 | pub struct TestPad(ObjectSubclass<imp::TestPad>) @extends Pad, crate::Object; |
126 | } |
127 | |
128 | impl TestPad { |
129 | pub fn new(name: &str, direction: PadDirection) -> Self { |
130 | glib::Object::builder() |
131 | .property("name" , name) |
132 | .property("direction" , direction) |
133 | .build() |
134 | } |
135 | } |
136 | |
137 | #[test ] |
138 | fn test_pad_subclass() { |
139 | crate::init().unwrap(); |
140 | |
141 | let pad = TestPad::new("test" , PadDirection::Src); |
142 | |
143 | assert_eq!(pad.name(), "test" ); |
144 | |
145 | let otherpad = Pad::builder(PadDirection::Sink).name("other-test" ).build(); |
146 | pad.link(&otherpad).unwrap(); |
147 | pad.unlink(&otherpad).unwrap(); |
148 | |
149 | let imp = pad.imp(); |
150 | assert!(imp.linked.load(atomic::Ordering::SeqCst)); |
151 | assert!(imp.unlinked.load(atomic::Ordering::SeqCst)); |
152 | } |
153 | } |
154 | |