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