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