gstreamer/subclass/
plugin.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3pub const MAJOR_VERSION: i32 = 1;
4
5cfg_if::cfg_if! {
6    if #[cfg(feature = "v1_22")] {
7        pub const MINOR_VERSION: i32 = 22;
8    } else if #[cfg(feature = "v1_20")] {
9        pub const MINOR_VERSION: i32 = 20;
10    } else if #[cfg(feature = "v1_18")] {
11        pub const MINOR_VERSION: i32 = 18;
12    } else if #[cfg(feature = "v1_16")] {
13        pub const MINOR_VERSION: i32 = 16;
14    } else {
15        pub const MINOR_VERSION: i32 = 14;
16    }
17}
18
19#[macro_export]
20macro_rules! plugin_define(
21    ($name:ident, $description:expr, $plugin_init:ident,
22     $version:expr, $license:expr, $source:expr,
23     $package:expr, $origin:expr $(, $release_datetime:expr)?) => {
24        pub mod plugin_desc {
25            #[repr(transparent)]
26            pub struct GstPluginDesc($crate::ffi::GstPluginDesc);
27            unsafe impl Send for GstPluginDesc {}
28            unsafe impl Sync for GstPluginDesc {}
29
30            static GST_PLUGIN_DESC: GstPluginDesc = GstPluginDesc($crate::ffi::GstPluginDesc {
31                major_version: $crate::subclass::MAJOR_VERSION,
32                minor_version: $crate::subclass::MINOR_VERSION,
33                name: concat!(stringify!($name), "\0") as *const str as *const _,
34                description: concat!($description, "\0") as *const str as *const _,
35                plugin_init: Some(plugin_init_trampoline),
36                version: concat!($version, "\0") as *const str as *const _,
37                license: concat!($license, "\0") as *const str as *const _,
38                source: concat!($source, "\0") as *const str as *const _,
39                package: concat!($package, "\0") as *const str as *const _,
40                origin: concat!($origin, "\0") as *const str as *const _,
41                release_datetime: {
42                    // NB: if this looks a lot like `Option`, it is not a coincidence. Alas,
43                    // Option::or is not `const` and neither is `unwrap_or` so we have to roll our
44                    // own oli-obk-ified enum instead.
45                    #[allow(unused)]
46                    enum OptionalPtr<T>{
47                        Null,
48                        Some(*const T),
49                    }
50                    #[allow(unused)]
51                    impl<T: Sized> OptionalPtr<T> {
52                        const fn with(self, value: *const T) -> Self {
53                            Self::Some(value)
54                        }
55                        const fn ptr(self) -> *const T {
56                            match self {
57                                Self::Null => std::ptr::null(),
58                                Self::Some(ptr) => ptr
59                            }
60                        }
61                    }
62                    OptionalPtr::Null
63                      $(.with(concat!($release_datetime, "\0").as_ptr() as _))?
64                        .ptr()
65                },
66                _gst_reserved: [0 as $crate::glib::ffi::gpointer; 4],
67            });
68
69            pub fn plugin_register_static() -> Result<(), $crate::glib::BoolError> {
70                unsafe {
71                    $crate::glib::result_from_gboolean!(
72                        $crate::ffi::gst_plugin_register_static(
73                            $crate::subclass::MAJOR_VERSION,
74                            $crate::subclass::MINOR_VERSION,
75                            concat!(stringify!($name), "\0") as *const str as *const _,
76                            concat!($description, "\0") as *const str as _,
77                            Some(plugin_init_trampoline),
78                            concat!($version, "\0") as *const str as *const _,
79                            concat!($license, "\0") as *const str as *const _,
80                            concat!($source, "\0") as *const str as *const _,
81                            concat!($package, "\0") as *const str as *const _,
82                            concat!($origin, "\0") as *const str as *const _,
83                        ),
84                        "Failed to register the plugin"
85                    )
86                }
87            }
88
89            $crate::pastey::item! {
90                #[no_mangle]
91                #[allow(clippy::missing_safety_doc)]
92                pub unsafe extern "C" fn [<gst_plugin_ $name _register>] () {
93                    let _ = plugin_register_static();
94                }
95
96                #[no_mangle]
97                #[allow(clippy::missing_safety_doc)]
98                pub unsafe extern "C" fn [<gst_plugin_ $name _get_desc>] () -> *const $crate::ffi::GstPluginDesc {
99                    &GST_PLUGIN_DESC.0
100                }
101            }
102
103            #[allow(clippy::missing_safety_doc)]
104            unsafe extern "C" fn plugin_init_trampoline(plugin: *mut $crate::ffi::GstPlugin) -> $crate::glib::ffi::gboolean {
105                let panic_result = std::panic::catch_unwind(
106                    std::panic::AssertUnwindSafe(|| super::$plugin_init(&$crate::glib::translate::from_glib_borrow(plugin)))
107                );
108
109                match panic_result {
110                    Ok(register_result) => match register_result {
111                        Ok(_) => $crate::glib::ffi::GTRUE,
112                        Err(err) => {
113                            $crate::error!($crate::CAT_PLUGIN_LOADING, "Failed to register plugin: {}", err);
114                            $crate::glib::ffi::GFALSE
115                        }
116                    }
117                    Err(err) => {
118                        let cause = err.downcast_ref::<&str>().copied()
119                            .or_else(|| err.downcast_ref::<String>().map(|s| s.as_str()));
120                        if let Some(cause) = cause {
121                            $crate::error!($crate::CAT_PLUGIN_LOADING, "Failed to initialize plugin due to panic: {}", cause);
122                        } else {
123                            $crate::error!($crate::CAT_PLUGIN_LOADING, "Failed to initialize plugin due to panic");
124                        }
125
126                        $crate::glib::ffi::GFALSE
127                    }
128                }
129            }
130        }
131        pub use self::plugin_desc::plugin_register_static;
132    };
133);
134
135#[cfg(test)]
136mod tests {
137    fn plugin_init(_plugin: &crate::Plugin) -> Result<(), glib::BoolError> {
138        Ok(())
139    }
140
141    crate::plugin_define!(
142        gst_rs_plugin_test,
143        env!("CARGO_PKG_DESCRIPTION"),
144        plugin_init,
145        env!("CARGO_PKG_VERSION"),
146        "MIT/X11",
147        env!("CARGO_PKG_NAME"),
148        env!("CARGO_PKG_NAME"),
149        env!("CARGO_PKG_REPOSITORY")
150    );
151
152    #[test]
153    fn plugin_register() {
154        crate::init().unwrap();
155        plugin_register_static().unwrap();
156    }
157}