use crate::{ffi, prelude::*, Formatter};
use glib::{subclass::prelude::*, translate::*};
pub trait FormatterImpl: FormatterImplExt + ObjectImpl + Send + Sync {
fn can_load_uri(&self, uri: &str) -> Result<(), glib::Error> {
self.parent_can_load_uri(uri)
}
fn load_from_uri(&self, timeline: &crate::Timeline, uri: &str) -> Result<(), glib::Error> {
self.parent_load_from_uri(timeline, uri)
}
fn save_to_uri(
&self,
timeline: &crate::Timeline,
uri: &str,
overwrite: bool,
) -> Result<(), glib::Error> {
self.parent_save_to_uri(timeline, uri, overwrite)
}
}
mod sealed {
pub trait Sealed {}
impl<T: super::FormatterImplExt> Sealed for T {}
}
pub trait FormatterImplExt: sealed::Sealed + ObjectSubclass {
fn parent_can_load_uri(&self, uri: &str) -> Result<(), glib::Error> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GESFormatterClass;
let f = (*parent_class)
.can_load_uri
.expect("Missing parent function `can_load_uri`");
let mut error = std::ptr::null_mut();
let res = f(
self.obj()
.unsafe_cast_ref::<crate::Formatter>()
.to_glib_none()
.0,
uri.to_glib_none().0,
&mut error,
);
if res == glib::ffi::GFALSE {
if error.is_null() {
Err(glib::Error::new(
gst::CoreError::Failed,
"Can load uri failed",
))
} else {
Err(from_glib_full(error))
}
} else {
Ok(())
}
}
}
fn parent_load_from_uri(
&self,
timeline: &crate::Timeline,
uri: &str,
) -> Result<(), glib::Error> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GESFormatterClass;
let f = (*parent_class)
.load_from_uri
.expect("Missing parent function `load_from_uri`");
let mut error = std::ptr::null_mut();
let res = f(
self.obj()
.unsafe_cast_ref::<crate::Formatter>()
.to_glib_none()
.0,
timeline
.unsafe_cast_ref::<crate::Timeline>()
.to_glib_none()
.0,
uri.to_glib_none().0,
&mut error,
);
if res == glib::ffi::GFALSE {
if error.is_null() {
Err(glib::Error::new(
gst::CoreError::Failed,
"Load from uri failed",
))
} else {
Err(from_glib_full(error))
}
} else {
Ok(())
}
}
}
fn parent_save_to_uri(
&self,
timeline: &crate::Timeline,
uri: &str,
overwrite: bool,
) -> Result<(), glib::Error> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GESFormatterClass;
let f = (*parent_class)
.save_to_uri
.expect("Missing parent function `save_to_uri`");
let mut error = std::ptr::null_mut();
let res = f(
self.obj()
.unsafe_cast_ref::<crate::Formatter>()
.to_glib_none()
.0,
timeline
.unsafe_cast_ref::<crate::Timeline>()
.to_glib_none()
.0,
uri.to_glib_none().0,
overwrite.into_glib(),
&mut error,
);
if res == glib::ffi::GFALSE {
if error.is_null() {
Err(glib::Error::new(
gst::CoreError::Failed,
"Save to uri failed",
))
} else {
Err(from_glib_full(error))
}
} else {
Ok(())
}
}
}
}
impl<T: FormatterImpl> FormatterImplExt for T {}
unsafe impl<T: FormatterImpl> IsSubclassable<T> for Formatter {
fn class_init(klass: &mut glib::Class<Self>) {
Self::parent_class_init::<T>(klass);
let klass = klass.as_mut();
klass.can_load_uri = Some(formatter_can_load_uri::<T>);
klass.load_from_uri = Some(formatter_load_from_uri::<T>);
klass.save_to_uri = Some(formatter_save_to_uri::<T>);
}
}
unsafe extern "C" fn formatter_can_load_uri<T: FormatterImpl>(
ptr: *mut ffi::GESFormatter,
uri: *const libc::c_char,
error: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
match imp.can_load_uri(glib::GString::from_glib_borrow(uri).as_str()) {
Err(err) => {
if !error.is_null() {
*error = err.into_glib_ptr();
}
glib::ffi::GFALSE
}
Ok(_) => glib::ffi::GTRUE,
}
}
unsafe extern "C" fn formatter_load_from_uri<T: FormatterImpl>(
ptr: *mut ffi::GESFormatter,
timeline: *mut ffi::GESTimeline,
uri: *const libc::c_char,
error: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
let timeline = from_glib_borrow(timeline);
match imp.load_from_uri(&timeline, glib::GString::from_glib_borrow(uri).as_str()) {
Err(err) => {
if !error.is_null() {
*error = err.into_glib_ptr();
}
glib::ffi::GFALSE
}
Ok(_) => glib::ffi::GTRUE,
}
}
unsafe extern "C" fn formatter_save_to_uri<T: FormatterImpl>(
ptr: *mut ffi::GESFormatter,
timeline: *mut ffi::GESTimeline,
uri: *const libc::c_char,
overwrite: glib::ffi::gboolean,
error: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
let timeline = from_glib_borrow(timeline);
match imp.save_to_uri(
&timeline,
glib::GString::from_glib_borrow(uri).as_str(),
from_glib(overwrite),
) {
Err(err) => {
if !error.is_null() {
*error = err.into_glib_ptr();
}
glib::ffi::GFALSE
}
Ok(_) => glib::ffi::GTRUE,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Formatter;
pub mod imp {
use super::*;
#[derive(Default)]
pub struct SimpleFormatter;
#[glib::object_subclass]
impl ObjectSubclass for SimpleFormatter {
const NAME: &'static str = "SimpleFormatter";
type Type = super::SimpleFormatter;
type ParentType = Formatter;
}
impl ObjectImpl for SimpleFormatter {}
impl FormatterImpl for SimpleFormatter {
fn can_load_uri(&self, uri: &str) -> Result<(), glib::Error> {
if uri.starts_with("ges:test") {
Ok(())
} else {
self.parent_can_load_uri(uri)
}
}
fn load_from_uri(
&self,
timeline: &crate::Timeline,
_uri: &str,
) -> Result<(), glib::Error> {
timeline.append_layer();
Ok(())
}
fn save_to_uri(
&self,
timeline: &crate::Timeline,
uri: &str,
_overwrite: bool,
) -> Result<(), glib::Error> {
unsafe { timeline.set_data("saved", uri.to_string()) };
Ok(())
}
}
}
glib::wrapper! {
pub struct SimpleFormatter(ObjectSubclass<imp::SimpleFormatter>) @extends Formatter, gst::Object;
}
impl SimpleFormatter {
pub fn new() -> Self {
glib::Object::builder().build()
}
}
impl Default for SimpleFormatter {
fn default() -> Self {
Self::new()
}
}
#[test]
fn test_formatter_subclass() {
crate::init().unwrap();
let formatter = SimpleFormatter::new();
formatter
.can_load_uri("ges:test:")
.expect("We can load anything...");
assert!(formatter.can_load_uri("nottest").is_err());
let timeline = crate::Timeline::new();
assert_eq!(timeline.layers().len(), 0);
#[allow(deprecated)]
formatter
.load_from_uri(&timeline, "test")
.expect("We can load anything...");
assert_eq!(timeline.layers().len(), 1);
unsafe {
assert_eq!(timeline.data::<Option<String>>("saved"), None);
}
#[allow(deprecated)]
formatter
.save_to_uri(&timeline, "test", false)
.expect("We can save anything...");
unsafe {
assert_eq!(
timeline.data::<String>("saved").unwrap().as_ref(),
&"test".to_string()
);
}
Formatter::register(
SimpleFormatter::static_type(),
"SimpleFormatter",
None,
None,
None,
1.0,
gst::Rank::PRIMARY,
);
let proj = crate::Project::new(Some("ges:test:"));
let timeline = proj
.extract()
.unwrap()
.downcast::<crate::Timeline>()
.unwrap();
assert_eq!(timeline.layers().len(), 1);
let proj = crate::Project::new(Some("ges:notest:"));
assert!(proj.extract().is_err());
}
}