Skip to main content

aviutl2\generic/
bridge.rs

1use crate::{
2    common::{AnyResult, LeakManager},
3    generic::{
4        GenericPlugin, ProjectFile,
5        binding::{HostAppHandle, PluginRegistry},
6    },
7};
8
9#[doc(hidden)]
10pub struct InternalGenericPluginState<T: Send + Sync + GenericPlugin> {
11    plugin_registry: PluginRegistry,
12
13    register_plugin_done: std::sync::Arc<std::sync::atomic::AtomicBool>,
14    global_leak_manager: LeakManager,
15
16    instance: T,
17    is_edit_handle_ready: std::sync::Arc<std::sync::atomic::AtomicBool>,
18}
19
20impl<T: Send + Sync + GenericPlugin> InternalGenericPluginState<T> {
21    pub fn new(instance: T) -> Self {
22        Self {
23            plugin_registry: PluginRegistry::new(),
24            register_plugin_done: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)),
25            global_leak_manager: LeakManager::new(),
26            instance,
27            is_edit_handle_ready: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)),
28        }
29    }
30}
31
32pub trait GenericSingleton
33where
34    Self: 'static + Send + Sync + crate::generic::GenericPlugin,
35{
36    fn __get_singleton_state() -> &'static std::sync::RwLock<
37        Option<crate::generic::__bridge::InternalGenericPluginState<Self>>,
38    >;
39    fn with_instance<R>(f: impl FnOnce(&Self) -> R) -> R {
40        let lock = Self::__get_singleton_state();
41        let guard = lock.read().unwrap();
42        let state = guard.as_ref().expect("Plugin not initialized");
43        f(&state.instance)
44    }
45    fn with_instance_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R {
46        let lock = Self::__get_singleton_state();
47        let mut guard = lock.write().unwrap();
48        let state = guard.as_mut().expect("Plugin not initialized");
49        f(&mut state.instance)
50    }
51}
52
53pub unsafe fn create_table<T: GenericSingleton>() -> *mut aviutl2_sys::plugin2::COMMON_PLUGIN_TABLE
54{
55    let plugin_state = T::__get_singleton_state();
56    let mut plugin_state = plugin_state.write().unwrap();
57    let plugin_state = plugin_state.as_mut().expect("Plugin not initialized");
58    tracing::info!(
59        "Creating plugin table for plugin: {}",
60        std::any::type_name::<T>()
61    );
62    let info = plugin_state.instance.plugin_info();
63    let table = Box::new(aviutl2_sys::plugin2::COMMON_PLUGIN_TABLE {
64        name: plugin_state
65            .global_leak_manager
66            .leak_as_wide_string(&info.name),
67        information: plugin_state
68            .global_leak_manager
69            .leak_as_wide_string(&info.information),
70    });
71    Box::into_raw(table)
72}
73
74pub unsafe fn create_table_unwind<T: GenericSingleton>()
75-> *mut aviutl2_sys::plugin2::COMMON_PLUGIN_TABLE {
76    match crate::utils::catch_unwind_with_panic_info(|| unsafe { create_table::<T>() }) {
77        Ok(table) => table,
78        Err(panic_info) => {
79            tracing::error!("Panic occurred during table creation: {}", panic_info);
80            let _ = crate::logger::write_error_log(&panic_info);
81            std::ptr::null_mut()
82        }
83    }
84}
85
86pub unsafe fn initialize_plugin_c<T: GenericSingleton>(version: u32) -> bool {
87    match initialize_plugin::<T>(version) {
88        Ok(_) => true,
89        Err(e) => {
90            tracing::error!("Failed to initialize plugin: {}", e);
91            let _ = crate::logger::write_error_log(&format!("{e}"));
92            false
93        }
94    }
95}
96
97pub unsafe fn initialize_plugin_c_unwind<T: GenericSingleton>(version: u32) -> bool {
98    match crate::utils::catch_unwind_with_panic_info(|| unsafe {
99        initialize_plugin_c::<T>(version)
100    }) {
101        Ok(result) => result,
102        Err(panic_info) => {
103            tracing::error!(
104                "Panic occurred during plugin initialization: {}",
105                panic_info
106            );
107            let _ = crate::logger::write_error_log(&panic_info);
108            false
109        }
110    }
111}
112
113pub(crate) fn initialize_plugin<T: GenericSingleton>(version: u32) -> AnyResult<()> {
114    crate::common::ensure_minimum_aviutl2_version(version.into())?;
115    let plugin_state = T::__get_singleton_state();
116    let info = crate::common::AviUtl2Info {
117        version: version.into(),
118    };
119    let internal = T::new(info)?;
120    let plugin = InternalGenericPluginState::new(internal);
121    *plugin_state.write().unwrap() = Some(plugin);
122
123    Ok(())
124}
125fn register_plugin_impl<T: GenericSingleton>(
126    host: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
127    unwind: bool,
128) {
129    let plugin_state = T::__get_singleton_state();
130    let mut plugin_state = plugin_state.write().unwrap();
131    let plugin_state = plugin_state.as_mut().expect("Plugin not initialized");
132
133    let mut handle = unsafe {
134        HostAppHandle::new(
135            host,
136            &mut plugin_state.global_leak_manager,
137            plugin_state.register_plugin_done.clone(),
138            &mut plugin_state.plugin_registry,
139            plugin_state.is_edit_handle_ready.clone(),
140        )
141    };
142    if unwind {
143        let result =
144            crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(|| {
145                T::register(&mut plugin_state.instance, &mut handle)
146            }));
147        if let Err(panic_info) = result {
148            tracing::error!(
149                "Panic occurred during plugin registration: {:?}",
150                panic_info
151            );
152            let _ = crate::logger::write_error_log(&format!(
153                "Panic during plugin registration: {}",
154                panic_info
155            ));
156            return;
157        }
158        handle.register_project_load_handler(on_project_load_impl::<T>);
159        handle.register_project_save_handler(on_project_save_impl::<T>);
160        handle.register_clear_cache_handler(on_clear_cache_impl::<T>);
161        // handle.register_change_scene_handler(on_change_scene_impl::<T>);
162    } else {
163        T::register(&mut plugin_state.instance, &mut handle);
164        handle.register_project_load_handler(on_project_load_impl::<T>);
165        handle.register_project_save_handler(on_project_save_impl::<T>);
166        handle.register_clear_cache_handler(on_clear_cache_impl::<T>);
167        // handle.register_change_scene_handler(on_change_scene_impl::<T>);
168    }
169    handle.register_event_listener(crate::generic::EventType::UpdateObject, || {
170        <T as GenericSingleton>::with_instance_mut(|instance| instance.event_update_object_info())
171    });
172    handle.register_event_listener(crate::generic::EventType::ChangeEditFrame, || {
173        <T as GenericSingleton>::with_instance_mut(|instance| instance.event_change_edit_frame())
174    });
175    handle.register_event_listener(crate::generic::EventType::ChangeEditScene, || {
176        <T as GenericSingleton>::with_instance_mut(|instance| instance.event_change_scene_info())
177    });
178    handle.register_event_listener(crate::generic::EventType::ChangeFocusObject, || {
179        <T as GenericSingleton>::with_instance_mut(|instance| instance.event_change_focus_object())
180    });
181    plugin_state
182        .register_plugin_done
183        .store(true, std::sync::atomic::Ordering::SeqCst);
184
185    fn on_project_load_impl<T: GenericSingleton>(project: &mut ProjectFile) {
186        {
187            // on_project_loadはプロジェクトの初期化時に呼ばれるので、RegisterPluginが終わった合図として使う。
188            let state = T::__get_singleton_state();
189            let guard = state.read().unwrap();
190            let plugin_state = guard.as_ref().expect("Plugin not initialized");
191            plugin_state
192                .is_edit_handle_ready
193                .store(true, std::sync::atomic::Ordering::SeqCst);
194        }
195        <T as GenericSingleton>::with_instance_mut(|instance| {
196            instance.on_project_load(project);
197        });
198    }
199
200    fn on_project_save_impl<T: GenericSingleton>(project: &mut ProjectFile) {
201        <T as GenericSingleton>::with_instance_mut(|instance| {
202            instance.on_project_save(project);
203        });
204    }
205
206    fn on_clear_cache_impl<T: GenericSingleton>(edit_section: &crate::generic::EditSection) {
207        <T as GenericSingleton>::with_instance_mut(|instance| {
208            instance.on_clear_cache(edit_section);
209        });
210    }
211
212    // ref: [GenericPlugin::on_change_scene]
213    //
214    // fn on_change_scene_impl<T: GenericSingleton>(edit_section: &crate::generic::EditSection) {
215    //     <T as GenericSingleton>::with_instance_mut(|instance| {
216    //         instance.on_change_scene(edit_section);
217    //     });
218    // }
219}
220
221pub unsafe fn register_plugin<T: GenericSingleton>(
222    host: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
223) {
224    register_plugin_impl::<T>(host, false);
225}
226
227pub unsafe fn register_plugin_unwind<T: GenericSingleton>(
228    host: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
229) {
230    if let Err(panic_info) =
231        crate::utils::catch_unwind_with_panic_info(|| register_plugin_impl::<T>(host, true))
232    {
233        tracing::error!("Panic occurred during register_plugin: {}", panic_info);
234        let _ = crate::logger::write_error_log(&panic_info);
235    }
236}
237pub unsafe fn uninitialize_plugin<T: GenericSingleton>() {
238    let plugin_state = T::__get_singleton_state();
239    let mut plugin_state = plugin_state.write().unwrap();
240    plugin_state.take();
241}
242
243pub unsafe fn uninitialize_plugin_c_unwind<T: GenericSingleton>() {
244    match crate::utils::catch_unwind_with_panic_info(|| unsafe { uninitialize_plugin::<T>() }) {
245        Ok(()) => {}
246        Err(panic_info) => {
247            tracing::error!(
248                "Panic occurred during plugin uninitialization: {}",
249                panic_info
250            );
251            let _ = crate::logger::write_error_log(&panic_info);
252        }
253    }
254}
255
256/// 汎用プラグインを登録するマクロ。
257///
258/// # Arguments
259///
260/// - `unwind`: panic時にunwindするかどうか。デフォルトは`true`。
261#[macro_export]
262macro_rules! register_generic_plugin {
263    ($struct:ident, $($key:ident = $value:expr),* $(,)?) => {
264        $crate::__internal_module! {
265            #[unsafe(no_mangle)]
266            unsafe extern "C" fn RequiredVersion() -> u32 {
267                $crate::MINIMUM_AVIUTL2_VERSION.into()
268            }
269
270            #[unsafe(no_mangle)]
271            unsafe extern "C" fn InitializeLogger(logger: *mut $crate::sys::logger2::LOG_HANDLE) {
272                $crate::comptime_if::comptime_if! {
273                    if unwind where (unwind = true, $( $key = $value ),* ) {
274                        $crate::logger::__initialize_logger_unwind(logger)
275                    } else {
276                        $crate::logger::__initialize_logger(logger)
277                    }
278                }
279            }
280
281            #[unsafe(no_mangle)]
282            unsafe extern "C" fn InitializeConfig(
283                config: *mut $crate::sys::config2::CONFIG_HANDLE
284            ) {
285                $crate::comptime_if::comptime_if! {
286                    if unwind where (unwind = true, $( $key = $value ),* ) {
287                        $crate::config::__initialize_config_handle_unwind(config)
288                    } else {
289                        $crate::config::__initialize_config_handle(config)
290                    }
291                }
292            }
293
294            #[unsafe(no_mangle)]
295            unsafe extern "C" fn InitializeCache(
296                cache: *mut $crate::sys::cache2::CACHE_HANDLE
297            ) {
298                $crate::comptime_if::comptime_if! {
299                    if unwind where (unwind = true, $( $key = $value ),* ) {
300                        $crate::cache::__initialize_cache_unwind(cache)
301                    } else {
302                        $crate::cache::__initialize_cache(cache)
303                    }
304                }
305            }
306
307            #[unsafe(no_mangle)]
308            unsafe extern "C" fn InitializePlugin(version: u32) -> bool {
309                unsafe {
310                    $crate::comptime_if::comptime_if! {
311                        if unwind where (unwind = true, $( $key = $value ),* ) {
312                            $crate::generic::__bridge::initialize_plugin_c_unwind::<$struct>(version)
313                        } else {
314                            $crate::generic::__bridge::initialize_plugin_c::<$struct>(version)
315                        }
316                    }
317                }
318            }
319
320            #[unsafe(no_mangle)]
321            unsafe extern "C" fn GetCommonPluginTable() -> *mut $crate::sys::plugin2::COMMON_PLUGIN_TABLE {
322                $crate::comptime_if::comptime_if! {
323                    if unwind where (unwind = true, $( $key = $value ),* ) {
324                        unsafe { $crate::generic::__bridge::create_table_unwind::<$struct>() }
325                    } else {
326                        unsafe { $crate::generic::__bridge::create_table::<$struct>() }
327                    }
328                }
329            }
330
331            #[unsafe(no_mangle)]
332            unsafe extern "C" fn UninitializePlugin() {
333                unsafe {
334                    $crate::comptime_if::comptime_if! {
335                        if unwind where (unwind = true, $( $key = $value ),* ) {
336                            $crate::generic::__bridge::uninitialize_plugin_c_unwind::<$struct>()
337                        } else {
338                            $crate::generic::__bridge::uninitialize_plugin::<$struct>()
339                        }
340                    }
341                };
342            }
343
344            #[unsafe(no_mangle)]
345            unsafe extern "C" fn RegisterPlugin(host: *mut aviutl2::sys::plugin2::HOST_APP_TABLE) {
346                $crate::comptime_if::comptime_if! {
347                    if unwind where (unwind = true, $( $key = $value ),* ) {
348                        unsafe { $crate::generic::__bridge::register_plugin_unwind::<$struct>(host) };
349                    } else {
350                        unsafe { $crate::generic::__bridge::register_plugin::<$struct>(host) };
351                    }
352                }
353            }
354        }
355    };
356    ($struct:ident, $($key:ident),* $(,)?) => {
357        $crate::register_generic_plugin!($struct, $( $key = true ),* );
358    };
359    ($struct:ident) => {
360        $crate::register_generic_plugin!($struct, );
361    };
362}