aviutl2\module/
bridge.rs

1use crate::{
2    common::{AnyResult, LeakManager, alert_error},
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: ScriptModule + Sized + Send + Sync + 'static,
28{
29    fn __get_singleton_state() -> &'static std::sync::RwLock<Option<InternalScriptModuleState<Self>>>;
30
31    fn with_instance<R>(f: impl FnOnce(&Self) -> R) -> R {
32        let lock = Self::__get_singleton_state();
33        let guard = lock.read().unwrap();
34        let state = guard.as_ref().expect("Plugin not initialized");
35        f(&state.instance)
36    }
37
38    fn with_instance_mut<R>(f: impl FnOnce(&mut Self) -> R) -> R {
39        let lock = Self::__get_singleton_state();
40        let mut guard = lock.write().unwrap();
41        let state = guard.as_mut().expect("Plugin not initialized");
42        f(&mut state.instance)
43    }
44}
45
46pub unsafe fn initialize_plugin_c<T: ScriptModuleSingleton>(version: u32) -> bool {
47    match initialize_plugin::<T>(version) {
48        Ok(_) => true,
49        Err(e) => {
50            log::error!("Failed to initialize plugin: {}", e);
51            alert_error(&e);
52            false
53        }
54    }
55}
56
57pub(crate) fn initialize_plugin<T: ScriptModuleSingleton>(version: u32) -> AnyResult<()> {
58    let plugin_state = T::__get_singleton_state();
59    let info = crate::common::AviUtl2Info {
60        version: version.into(),
61    };
62    let internal = T::new(info)?;
63    let plugin = InternalScriptModuleState::new(internal);
64    *plugin_state.write().unwrap() = Some(plugin);
65
66    Ok(())
67}
68pub unsafe fn uninitialize_plugin<T: ScriptModuleSingleton>() {
69    let plugin_state = T::__get_singleton_state();
70    *plugin_state.write().unwrap() = None;
71}
72
73pub unsafe fn create_table<T: ScriptModuleSingleton>()
74-> *mut aviutl2_sys::module2::SCRIPT_MODULE_TABLE {
75    let plugin_state_lock = T::__get_singleton_state();
76    let plugin_state = plugin_state_lock.read().unwrap();
77    let plugin_state = plugin_state.as_ref().expect("Plugin not initialized");
78    let plugin_info = &plugin_state.plugin_info;
79    let information = if cfg!(debug_assertions) {
80        format!("(Debug Build) {}", plugin_info.information)
81    } else {
82        plugin_info.information.clone()
83    };
84
85    let module_functions: Vec<aviutl2_sys::module2::SCRIPT_MODULE_FUNCTION> = plugin_info
86        .functions
87        .iter()
88        .map(|f| aviutl2_sys::module2::SCRIPT_MODULE_FUNCTION {
89            name: plugin_state
90                .global_leak_manager
91                .leak_as_wide_string(&f.name),
92            func: f.func,
93        })
94        .chain(std::iter::once(
95            aviutl2_sys::module2::SCRIPT_MODULE_FUNCTION {
96                name: std::ptr::null(),
97                func: unreachable_function,
98            },
99        ))
100        .collect();
101    let functions_ptr = plugin_state
102        .global_leak_manager
103        .leak_value_vec(module_functions);
104
105    // NOTE: プラグイン名などの文字列はAviUtlが終了するまで解放しない
106    let table = aviutl2_sys::module2::SCRIPT_MODULE_TABLE {
107        information: plugin_state
108            .global_leak_manager
109            .leak_as_wide_string(&information),
110        functions: functions_ptr,
111    };
112    let table = Box::new(table);
113    Box::leak(table)
114}
115
116extern "C" fn unreachable_function(_: *mut aviutl2_sys::module2::SCRIPT_MODULE_PARAM) {
117    unreachable!("This function should never be called");
118}
119
120/// スクリプトモジュールを登録するマクロ。
121#[macro_export]
122macro_rules! register_script_module {
123    ($struct:ident) => {
124        ::aviutl2::__internal_module! {
125            #[unsafe(no_mangle)]
126            unsafe extern "C" fn InitializeLogger(logger: *mut $crate::sys::logger2::LOG_HANDLE) {
127                $crate::logger::__initialize_logger(logger)
128            }
129
130            #[unsafe(no_mangle)]
131            unsafe extern "C" fn InitializePlugin(version: u32) -> bool {
132                unsafe { $crate::module::__bridge::initialize_plugin_c::<$struct>(version) }
133            }
134
135            #[unsafe(no_mangle)]
136            unsafe extern "C" fn UninitializePlugin() {
137                unsafe { $crate::module::__bridge::uninitialize_plugin::<$struct>() }
138            }
139
140            #[unsafe(no_mangle)]
141            unsafe extern "C" fn GetScriptModuleTable()
142            -> *mut aviutl2::sys::module2::SCRIPT_MODULE_TABLE {
143                unsafe { $crate::module::__bridge::create_table::<$struct>() }
144            }
145        }
146    };
147}