Skip to main content

gstreamer/subclass/
pad.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use 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}