1 // Copyright (C) 2017,2018 Sebastian Dröge <sebastian@centricular.com>
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8 
9 use glib_sys;
10 use gst_sys;
11 
12 use glib::translate::*;
13 
14 use super::prelude::*;
15 use glib::subclass::prelude::*;
16 
17 use Bin;
18 use BinClass;
19 use Element;
20 use LoggableError;
21 use Message;
22 
23 pub trait BinImpl: BinImplExt + ElementImpl + Send + Sync + 'static {
add_element(&self, bin: &Bin, element: &Element) -> Result<(), LoggableError>24     fn add_element(&self, bin: &Bin, element: &Element) -> Result<(), LoggableError> {
25         self.parent_add_element(bin, element)
26     }
27 
remove_element(&self, bin: &Bin, element: &Element) -> Result<(), LoggableError>28     fn remove_element(&self, bin: &Bin, element: &Element) -> Result<(), LoggableError> {
29         self.parent_remove_element(bin, element)
30     }
31 
handle_message(&self, bin: &Bin, message: Message)32     fn handle_message(&self, bin: &Bin, message: Message) {
33         self.parent_handle_message(bin, message)
34     }
35 }
36 
37 pub trait BinImplExt {
parent_add_element(&self, bin: &Bin, element: &Element) -> Result<(), LoggableError>38     fn parent_add_element(&self, bin: &Bin, element: &Element) -> Result<(), LoggableError>;
39 
parent_remove_element(&self, bin: &Bin, element: &Element) -> Result<(), LoggableError>40     fn parent_remove_element(&self, bin: &Bin, element: &Element) -> Result<(), LoggableError>;
41 
parent_handle_message(&self, bin: &Bin, message: Message)42     fn parent_handle_message(&self, bin: &Bin, message: Message);
43 }
44 
45 impl<T: BinImpl + ObjectImpl> BinImplExt for T {
parent_add_element(&self, bin: &Bin, element: &Element) -> Result<(), LoggableError>46     fn parent_add_element(&self, bin: &Bin, element: &Element) -> Result<(), LoggableError> {
47         unsafe {
48             let data = self.get_type_data();
49             let parent_class = data.as_ref().get_parent_class() as *mut gst_sys::GstBinClass;
50             let f = (*parent_class).add_element.ok_or_else(|| {
51                 gst_loggable_error!(::CAT_RUST, "Parent function `add_element` is not defined")
52             })?;
53             gst_result_from_gboolean!(
54                 f(bin.to_glib_none().0, element.to_glib_none().0),
55                 ::CAT_RUST,
56                 "Failed to add the element using the parent function"
57             )
58         }
59     }
60 
parent_remove_element(&self, bin: &Bin, element: &Element) -> Result<(), LoggableError>61     fn parent_remove_element(&self, bin: &Bin, element: &Element) -> Result<(), LoggableError> {
62         unsafe {
63             let data = self.get_type_data();
64             let parent_class = data.as_ref().get_parent_class() as *mut gst_sys::GstBinClass;
65             let f = (*parent_class).remove_element.ok_or_else(|| {
66                 gst_loggable_error!(
67                     ::CAT_RUST,
68                     "Parent function `remove_element` is not defined"
69                 )
70             })?;
71             gst_result_from_gboolean!(
72                 f(bin.to_glib_none().0, element.to_glib_none().0),
73                 ::CAT_RUST,
74                 "Failed to remove the element using the parent function"
75             )
76         }
77     }
78 
parent_handle_message(&self, bin: &Bin, message: Message)79     fn parent_handle_message(&self, bin: &Bin, message: Message) {
80         unsafe {
81             let data = self.get_type_data();
82             let parent_class = data.as_ref().get_parent_class() as *mut gst_sys::GstBinClass;
83             if let Some(ref f) = (*parent_class).handle_message {
84                 f(bin.to_glib_none().0, message.into_ptr());
85             }
86         }
87     }
88 }
89 
90 unsafe impl<T: ObjectSubclass + BinImpl> IsSubclassable<T> for BinClass
91 where
92     <T as ObjectSubclass>::Instance: PanicPoison,
93 {
override_vfuncs(&mut self)94     fn override_vfuncs(&mut self) {
95         <::ElementClass as IsSubclassable<T>>::override_vfuncs(self);
96         unsafe {
97             let klass = &mut *(self as *mut Self as *mut gst_sys::GstBinClass);
98             klass.add_element = Some(bin_add_element::<T>);
99             klass.remove_element = Some(bin_remove_element::<T>);
100             klass.handle_message = Some(bin_handle_message::<T>);
101         }
102     }
103 }
104 
bin_add_element<T: ObjectSubclass>( ptr: *mut gst_sys::GstBin, element: *mut gst_sys::GstElement, ) -> glib_sys::gboolean where T: BinImpl, T::Instance: PanicPoison,105 unsafe extern "C" fn bin_add_element<T: ObjectSubclass>(
106     ptr: *mut gst_sys::GstBin,
107     element: *mut gst_sys::GstElement,
108 ) -> glib_sys::gboolean
109 where
110     T: BinImpl,
111     T::Instance: PanicPoison,
112 {
113     let instance = &*(ptr as *mut T::Instance);
114     let imp = instance.get_impl();
115     let wrap: Bin = from_glib_borrow(ptr);
116 
117     gst_panic_to_error!(&wrap, &instance.panicked(), false, {
118         match imp.add_element(&wrap, &from_glib_none(element)) {
119             Ok(()) => true,
120             Err(err) => {
121                 err.log_with_object(&wrap);
122                 false
123             }
124         }
125     })
126     .to_glib()
127 }
128 
bin_remove_element<T: ObjectSubclass>( ptr: *mut gst_sys::GstBin, element: *mut gst_sys::GstElement, ) -> glib_sys::gboolean where T: BinImpl, T::Instance: PanicPoison,129 unsafe extern "C" fn bin_remove_element<T: ObjectSubclass>(
130     ptr: *mut gst_sys::GstBin,
131     element: *mut gst_sys::GstElement,
132 ) -> glib_sys::gboolean
133 where
134     T: BinImpl,
135     T::Instance: PanicPoison,
136 {
137     let instance = &*(ptr as *mut T::Instance);
138     let imp = instance.get_impl();
139     let wrap: Bin = from_glib_borrow(ptr);
140 
141     // If we get a floating reference passed simply return FALSE here. It can't be
142     // stored inside this bin, and if we continued to use it we would take ownership
143     // of this floating reference.
144     if gobject_sys::g_object_is_floating(element as *mut gobject_sys::GObject) != glib_sys::GFALSE {
145         return glib_sys::GFALSE;
146     }
147 
148     gst_panic_to_error!(&wrap, &instance.panicked(), false, {
149         match imp.remove_element(&wrap, &from_glib_none(element)) {
150             Ok(()) => true,
151             Err(err) => {
152                 err.log_with_object(&wrap);
153                 false
154             }
155         }
156     })
157     .to_glib()
158 }
159 
bin_handle_message<T: ObjectSubclass>( ptr: *mut gst_sys::GstBin, message: *mut gst_sys::GstMessage, ) where T: BinImpl, T::Instance: PanicPoison,160 unsafe extern "C" fn bin_handle_message<T: ObjectSubclass>(
161     ptr: *mut gst_sys::GstBin,
162     message: *mut gst_sys::GstMessage,
163 ) where
164     T: BinImpl,
165     T::Instance: PanicPoison,
166 {
167     let instance = &*(ptr as *mut T::Instance);
168     let imp = instance.get_impl();
169     let wrap: Bin = from_glib_borrow(ptr);
170 
171     gst_panic_to_error!(&wrap, &instance.panicked(), (), {
172         imp.handle_message(&wrap, from_glib_full(message))
173     });
174 }
175