gstreamer_editing_services/subclass/
formatter.rs1use 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}