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