Skip to main content

aviutl2\module/
bridge.rs

1use crate::{
2    common::{AnyResult, LeakManager},
3    module::{ScriptModule, ScriptModuleTable},
4};
5
6#[doc(hidden)]
7pub struct InternalScriptModuleState<T: Send + Sync + ScriptModule> {
8    plugin_info: ScriptModuleTable,
9    global_leak_manager: LeakManager,
10
11    pub instance: T,
12}
13
14impl<T: Send + Sync + ScriptModule> InternalScriptModuleState<T> {
15    pub fn new(instance: T) -> Self {
16        let plugin_info = instance.plugin_info();
17        Self {
18            plugin_info,
19            global_leak_manager: LeakManager::new(),
20            instance,
21        }
22    }
23}
24
25pub trait ScriptModuleSingleton
26where
27    Self: crate::module::ScriptModule + Sized + Send + Sync + 'static,
28{
29    fn __get_singleton_state()
30    -> &'static std::sync::RwLock<Option<crate::module::__bridge::InternalScriptModuleState<Self>>>;
31
32    fn with_instance<R>(f: impl FnOnce(&Self) -> R) -> R {
33        let lock = Self::__get_singleton_state();
34        let guard = lock.read().unwrap();
35        let state = guard.as_ref().expect("Plugin not initialized");
36        f(&state.instance)
37    }
38
39    fn with_instance_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R {
40        let lock = Self::__get_singleton_state();
41        let mut guard = lock.write().unwrap();
42        let state = guard.as_mut().expect("Plugin not initialized");
43        f(&mut state.instance)
44    }
45}
46
47pub unsafe fn initialize_plugin_c<T: ScriptModuleSingleton>(version: u32) -> bool {
48    match initialize_plugin::<T>(version) {
49        Ok(_) => true,
50        Err(e) => {
51            tracing::error!("Failed to initialize plugin: {}", e);
52            let _ = crate::logger::write_error_log(&format!("{e}"));
53            false
54        }
55    }
56}
57
58pub unsafe fn initialize_plugin_c_unwind<T: ScriptModuleSingleton>(version: u32) -> bool {
59    match crate::utils::catch_unwind_with_panic_info(|| unsafe {
60        initialize_plugin_c::<T>(version)
61    }) {
62        Ok(result) => result,
63        Err(panic_info) => {
64            tracing::error!(
65                "Panic occurred during plugin initialization: {}",
66                panic_info
67            );
68            let _ = crate::logger::write_error_log(&panic_info);
69            false
70        }
71    }
72}
73
74pub(crate) fn initialize_plugin<T: ScriptModuleSingleton>(version: u32) -> AnyResult<()> {
75    crate::common::ensure_minimum_aviutl2_version(version.into())?;
76    let plugin_state = T::__get_singleton_state();
77    let info = crate::common::AviUtl2Info {
78        version: version.into(),
79    };
80    let internal = T::new(info)?;
81    let plugin = InternalScriptModuleState::new(internal);
82    *plugin_state.write().unwrap() = Some(plugin);
83
84    Ok(())
85}
86pub unsafe fn uninitialize_plugin<T: ScriptModuleSingleton>() {
87    let plugin_state = T::__get_singleton_state();
88    *plugin_state.write().unwrap() = None;
89}
90
91pub unsafe fn uninitialize_plugin_c_unwind<T: ScriptModuleSingleton>() {
92    match crate::utils::catch_unwind_with_panic_info(|| unsafe { uninitialize_plugin::<T>() }) {
93        Ok(()) => {}
94        Err(panic_info) => {
95            tracing::error!(
96                "Panic occurred during plugin uninitialization: {}",
97                panic_info
98            );
99            let _ = crate::logger::write_error_log(&panic_info);
100        }
101    }
102}
103
104pub unsafe fn create_table<T: ScriptModuleSingleton>()
105-> *mut aviutl2_sys::module2::SCRIPT_MODULE_TABLE {
106    let plugin_state_lock = T::__get_singleton_state();
107    let plugin_state = plugin_state_lock.read().unwrap();
108    let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
109    let plugin_info = &plugin_state.plugin_info;
110    let information = plugin_info.information.clone();
111
112    let module_functions: Vec<aviutl2_sys::module2::SCRIPT_MODULE_FUNCTION> = plugin_info
113        .functions
114        .iter()
115        .map(|f| aviutl2_sys::module2::SCRIPT_MODULE_FUNCTION {
116            name: plugin_state
117                .global_leak_manager
118                .leak_as_wide_string(&f.name),
119            func: f.func,
120        })
121        .chain(std::iter::once(
122            aviutl2_sys::module2::SCRIPT_MODULE_FUNCTION {
123                name: std::ptr::null(),
124                func: unreachable_function,
125            },
126        ))
127        .collect();
128    let functions_ptr = plugin_state
129        .global_leak_manager
130        .leak_value_vec(module_functions);
131
132    // NOTE: プラグイン名などの文字列はAviUtlが終了するまで解放しない
133    let table = aviutl2_sys::module2::SCRIPT_MODULE_TABLE {
134        information: plugin_state
135            .global_leak_manager
136            .leak_as_wide_string(&information),
137        functions: functions_ptr,
138    };
139    let table = Box::new(table);
140    Box::leak(table)
141}
142
143pub unsafe fn create_table_unwind<T: ScriptModuleSingleton>()
144-> *mut aviutl2_sys::module2::SCRIPT_MODULE_TABLE {
145    match crate::utils::catch_unwind_with_panic_info(|| unsafe { create_table::<T>() }) {
146        Ok(table) => table,
147        Err(panic_info) => {
148            tracing::error!("Panic occurred during create_table: {}", panic_info);
149            let _ = crate::logger::write_error_log(&panic_info);
150            std::ptr::null_mut()
151        }
152    }
153}
154
155extern "C" fn unreachable_function(_: *mut aviutl2_sys::module2::SCRIPT_MODULE_PARAM) {
156    unreachable!("This function should never be called");
157}
158
159/// スクリプトモジュールを登録するマクロ。
160///
161/// # Arguments
162///
163/// - `unwind`: panic時にunwindするかどうか。デフォルトは`true`。
164#[macro_export]
165macro_rules! register_script_module {
166    ($struct:ident, $($key:ident = $value:expr),* $(,)?) => {
167        $crate::__internal_module! {
168            #[unsafe(no_mangle)]
169            unsafe extern "C" fn RequiredVersion() -> u32 {
170                $crate::MINIMUM_AVIUTL2_VERSION.into()
171            }
172
173            #[unsafe(no_mangle)]
174            unsafe extern "C" fn InitializeLogger(logger: *mut $crate::sys::logger2::LOG_HANDLE) {
175                $crate::comptime_if::comptime_if! {
176                    if unwind where (unwind = true, $( $key = $value ),* ) {
177                        $crate::logger::__initialize_logger_unwind(logger)
178                    } else {
179                        $crate::logger::__initialize_logger(logger)
180                    }
181                }
182            }
183
184            #[unsafe(no_mangle)]
185            unsafe extern "C" fn InitializeConfig(
186                config: *mut $crate::sys::config2::CONFIG_HANDLE
187            ) {
188                $crate::comptime_if::comptime_if! {
189                    if unwind where (unwind = true, $( $key = $value ),* ) {
190                        $crate::config::__initialize_config_handle_unwind(config)
191                    } else {
192                        $crate::config::__initialize_config_handle(config)
193                    }
194                }
195            }
196
197            #[unsafe(no_mangle)]
198            unsafe extern "C" fn InitializePlugin(version: u32) -> bool {
199                unsafe {
200                    $crate::comptime_if::comptime_if! {
201                        if unwind where (unwind = true, $( $key = $value ),* ) {
202                            $crate::module::__bridge::initialize_plugin_c_unwind::<$struct>(version)
203                        } else {
204                            $crate::module::__bridge::initialize_plugin_c::<$struct>(version)
205                        }
206                    }
207                }
208            }
209
210            #[unsafe(no_mangle)]
211            unsafe extern "C" fn UninitializePlugin() {
212                unsafe {
213                    $crate::comptime_if::comptime_if! {
214                        if unwind where (unwind = true, $( $key = $value ),* ) {
215                            $crate::module::__bridge::uninitialize_plugin_c_unwind::<$struct>()
216                        } else {
217                            $crate::module::__bridge::uninitialize_plugin::<$struct>()
218                        }
219                    }
220                }
221            }
222
223            #[unsafe(no_mangle)]
224            unsafe extern "C" fn GetScriptModuleTable()
225            -> *mut aviutl2::sys::module2::SCRIPT_MODULE_TABLE {
226                $crate::comptime_if::comptime_if! {
227                    if unwind where (unwind = true, $( $key = $value ),* ) {
228                        unsafe { $crate::module::__bridge::create_table_unwind::<$struct>() }
229                    } else {
230                        unsafe { $crate::module::__bridge::create_table::<$struct>() }
231                    }
232                }
233            }
234        }
235    };
236    ($struct:ident, $($key:ident),* $(,)?) => {
237        $crate::register_script_module!($struct, $( $key = true ),* );
238    };
239    ($struct:ident) => {
240        $crate::register_script_module!($struct, );
241    };
242}