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 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#[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}