gstreamer_editing_services/subclass/
formatter.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::{ffi, prelude::*, Formatter};
4use glib::{subclass::prelude::*, translate::*};
5
6pub trait FormatterImpl: ObjectImpl + ObjectSubclass<Type: IsA<Formatter>> + Send + Sync {
7    fn can_load_uri(&self, uri: &str) -> Result<(), glib::Error> {
8        self.parent_can_load_uri(uri)
9    }
10
11    fn load_from_uri(&self, timeline: &crate::Timeline, uri: &str) -> Result<(), glib::Error> {
12        self.parent_load_from_uri(timeline, uri)
13    }
14
15    fn save_to_uri(
16        &self,
17        timeline: &crate::Timeline,
18        uri: &str,
19        overwrite: bool,
20    ) -> Result<(), glib::Error> {
21        self.parent_save_to_uri(timeline, uri, overwrite)
22    }
23}
24
25pub trait FormatterImplExt: FormatterImpl {
26    fn parent_can_load_uri(&self, uri: &str) -> Result<(), glib::Error> {
27        unsafe {
28            let data = Self::type_data();
29            let parent_class = data.as_ref().parent_class() as *mut ffi::GESFormatterClass;
30
31            let f = (*parent_class)
32                .can_load_uri
33                .expect("Missing parent function `can_load_uri`");
34
35            let mut error = std::ptr::null_mut();
36            let res = f(
37                self.obj()
38                    .unsafe_cast_ref::<crate::Formatter>()
39                    .to_glib_none()
40                    .0,
41                uri.to_glib_none().0,
42                &mut error,
43            );
44
45            if res == glib::ffi::GFALSE {
46                if error.is_null() {
47                    Err(glib::Error::new(
48                        gst::CoreError::Failed,
49                        "Can load uri failed",
50                    ))
51                } else {
52                    Err(from_glib_full(error))
53                }
54            } else {
55                Ok(())
56            }
57        }
58    }
59
60    fn parent_load_from_uri(
61        &self,
62        timeline: &crate::Timeline,
63        uri: &str,
64    ) -> Result<(), glib::Error> {
65        unsafe {
66            let data = Self::type_data();
67            let parent_class = data.as_ref().parent_class() as *mut ffi::GESFormatterClass;
68
69            let f = (*parent_class)
70                .load_from_uri
71                .expect("Missing parent function `load_from_uri`");
72
73            let mut error = std::ptr::null_mut();
74            let res = f(
75                self.obj()
76                    .unsafe_cast_ref::<crate::Formatter>()
77                    .to_glib_none()
78                    .0,
79                timeline
80                    .unsafe_cast_ref::<crate::Timeline>()
81                    .to_glib_none()
82                    .0,
83                uri.to_glib_none().0,
84                &mut error,
85            );
86
87            if res == glib::ffi::GFALSE {
88                if error.is_null() {
89                    Err(glib::Error::new(
90                        gst::CoreError::Failed,
91                        "Load from uri failed",
92                    ))
93                } else {
94                    Err(from_glib_full(error))
95                }
96            } else {
97                Ok(())
98            }
99        }
100    }
101    fn parent_save_to_uri(
102        &self,
103        timeline: &crate::Timeline,
104        uri: &str,
105        overwrite: bool,
106    ) -> Result<(), glib::Error> {
107        unsafe {
108            let data = Self::type_data();
109            let parent_class = data.as_ref().parent_class() as *mut ffi::GESFormatterClass;
110
111            let f = (*parent_class)
112                .save_to_uri
113                .expect("Missing parent function `save_to_uri`");
114
115            let mut error = std::ptr::null_mut();
116            let res = f(
117                self.obj()
118                    .unsafe_cast_ref::<crate::Formatter>()
119                    .to_glib_none()
120                    .0,
121                timeline
122                    .unsafe_cast_ref::<crate::Timeline>()
123                    .to_glib_none()
124                    .0,
125                uri.to_glib_none().0,
126                overwrite.into_glib(),
127                &mut error,
128            );
129
130            if res == glib::ffi::GFALSE {
131                if error.is_null() {
132                    Err(glib::Error::new(
133                        gst::CoreError::Failed,
134                        "Save to uri failed",
135                    ))
136                } else {
137                    Err(from_glib_full(error))
138                }
139            } else {
140                Ok(())
141            }
142        }
143    }
144}
145
146impl<T: FormatterImpl> FormatterImplExt for T {}
147
148unsafe impl<T: FormatterImpl> IsSubclassable<T> for Formatter {
149    fn class_init(klass: &mut glib::Class<Self>) {
150        Self::parent_class_init::<T>(klass);
151        let klass = klass.as_mut();
152        klass.can_load_uri = Some(formatter_can_load_uri::<T>);
153        klass.load_from_uri = Some(formatter_load_from_uri::<T>);
154        klass.save_to_uri = Some(formatter_save_to_uri::<T>);
155    }
156}
157
158unsafe extern "C" fn formatter_can_load_uri<T: FormatterImpl>(
159    ptr: *mut ffi::GESFormatter,
160    uri: *const libc::c_char,
161    error: *mut *mut glib::ffi::GError,
162) -> glib::ffi::gboolean {
163    let instance = &*(ptr as *mut T::Instance);
164    let imp = instance.imp();
165
166    match imp.can_load_uri(glib::GString::from_glib_borrow(uri).as_str()) {
167        Err(err) => {
168            if !error.is_null() {
169                *error = err.into_glib_ptr();
170            }
171
172            glib::ffi::GFALSE
173        }
174        Ok(_) => glib::ffi::GTRUE,
175    }
176}
177
178unsafe extern "C" fn formatter_load_from_uri<T: FormatterImpl>(
179    ptr: *mut ffi::GESFormatter,
180    timeline: *mut ffi::GESTimeline,
181    uri: *const libc::c_char,
182    error: *mut *mut glib::ffi::GError,
183) -> glib::ffi::gboolean {
184    let instance = &*(ptr as *mut T::Instance);
185    let imp = instance.imp();
186    let timeline = from_glib_borrow(timeline);
187
188    match imp.load_from_uri(&timeline, glib::GString::from_glib_borrow(uri).as_str()) {
189        Err(err) => {
190            if !error.is_null() {
191                *error = err.into_glib_ptr();
192            }
193
194            glib::ffi::GFALSE
195        }
196        Ok(_) => glib::ffi::GTRUE,
197    }
198}
199
200unsafe extern "C" fn formatter_save_to_uri<T: FormatterImpl>(
201    ptr: *mut ffi::GESFormatter,
202    timeline: *mut ffi::GESTimeline,
203    uri: *const libc::c_char,
204    overwrite: glib::ffi::gboolean,
205    error: *mut *mut glib::ffi::GError,
206) -> glib::ffi::gboolean {
207    let instance = &*(ptr as *mut T::Instance);
208    let imp = instance.imp();
209    let timeline = from_glib_borrow(timeline);
210
211    match imp.save_to_uri(
212        &timeline,
213        glib::GString::from_glib_borrow(uri).as_str(),
214        from_glib(overwrite),
215    ) {
216        Err(err) => {
217            if !error.is_null() {
218                *error = err.into_glib_ptr();
219            }
220
221            glib::ffi::GFALSE
222        }
223        Ok(_) => glib::ffi::GTRUE,
224    }
225}
226
227#[cfg(test)]
228mod tests {
229    use super::*;
230    use crate::Formatter;
231
232    pub mod imp {
233        use super::*;
234
235        #[derive(Default)]
236        pub struct SimpleFormatter;
237
238        #[glib::object_subclass]
239        impl ObjectSubclass for SimpleFormatter {
240            const NAME: &'static str = "SimpleFormatter";
241            type Type = super::SimpleFormatter;
242            type ParentType = Formatter;
243        }
244        impl ObjectImpl for SimpleFormatter {}
245        impl FormatterImpl for SimpleFormatter {
246            fn can_load_uri(&self, uri: &str) -> Result<(), glib::Error> {
247                if uri.starts_with("ges:test") {
248                    Ok(())
249                } else {
250                    self.parent_can_load_uri(uri)
251                }
252            }
253
254            fn load_from_uri(
255                &self,
256                timeline: &crate::Timeline,
257                _uri: &str,
258            ) -> Result<(), glib::Error> {
259                timeline.append_layer();
260
261                Ok(())
262            }
263
264            fn save_to_uri(
265                &self,
266                timeline: &crate::Timeline,
267                uri: &str,
268                _overwrite: bool,
269            ) -> Result<(), glib::Error> {
270                unsafe { timeline.set_data("saved", uri.to_string()) };
271
272                Ok(())
273            }
274        }
275    }
276
277    glib::wrapper! {
278        pub struct SimpleFormatter(ObjectSubclass<imp::SimpleFormatter>) @extends Formatter, gst::Object;
279    }
280
281    impl SimpleFormatter {
282        pub fn new() -> Self {
283            glib::Object::builder().build()
284        }
285    }
286
287    impl Default for SimpleFormatter {
288        fn default() -> Self {
289            Self::new()
290        }
291    }
292
293    #[test]
294    fn test_formatter_subclass() {
295        crate::init().unwrap();
296
297        let formatter = SimpleFormatter::new();
298        formatter
299            .can_load_uri("ges:test:")
300            .expect("We can load anything...");
301
302        assert!(formatter.can_load_uri("nottest").is_err());
303
304        let timeline = crate::Timeline::new();
305        assert_eq!(timeline.layers().len(), 0);
306        #[allow(deprecated)]
307        formatter
308            .load_from_uri(&timeline, "test")
309            .expect("We can load anything...");
310        assert_eq!(timeline.layers().len(), 1);
311
312        unsafe {
313            assert_eq!(timeline.data::<Option<String>>("saved"), None);
314        }
315        #[allow(deprecated)]
316        formatter
317            .save_to_uri(&timeline, "test", false)
318            .expect("We can save anything...");
319        unsafe {
320            assert_eq!(
321                timeline.data::<String>("saved").unwrap().as_ref(),
322                &"test".to_string()
323            );
324        }
325
326        Formatter::register(
327            SimpleFormatter::static_type(),
328            "SimpleFormatter",
329            None,
330            None,
331            None,
332            1.0,
333            gst::Rank::PRIMARY,
334        );
335
336        let proj = crate::Project::new(Some("ges:test:"));
337        let timeline = proj
338            .extract()
339            .unwrap()
340            .downcast::<crate::Timeline>()
341            .unwrap();
342        assert_eq!(timeline.layers().len(), 1);
343
344        let proj = crate::Project::new(Some("ges:notest:"));
345        assert!(proj.extract().is_err());
346    }
347}