aviutl2\generic/
bridge.rs1use 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 kill_switch: 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 kill_switch: 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 kill_switch = plugin_state.kill_switch.clone();
134 let is_edithandle_ready = plugin_state.is_edit_handle_ready.clone();
135 let mut handle = unsafe {
136 HostAppHandle::new(
137 host,
138 &mut plugin_state.global_leak_manager,
139 kill_switch,
140 &mut plugin_state.plugin_registry,
141 is_edithandle_ready.clone(),
142 )
143 };
144 if unwind {
145 let result =
146 crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(|| {
147 T::register(&mut plugin_state.instance, &mut handle)
148 }));
149 if let Err(panic_info) = result {
150 tracing::error!("Panic occurred during plugin registration: {}", panic_info);
151 let _ = crate::logger::write_error_log(&format!(
152 "Panic during plugin registration: {}",
153 panic_info
154 ));
155 return;
156 }
157 handle.register_project_load_handler(on_project_load_unwind::<T>);
158 handle.register_project_save_handler(on_project_save_unwind::<T>);
159 handle.register_clear_cache_handler(on_clear_cache_unwind::<T>);
160 handle.register_change_scene_handler(on_change_scene_unwind::<T>);
161 } else {
162 T::register(&mut plugin_state.instance, &mut handle);
163 handle.register_project_load_handler(on_project_load::<T>);
164 handle.register_project_save_handler(on_project_save::<T>);
165 handle.register_clear_cache_handler(on_clear_cache::<T>);
166 handle.register_change_scene_handler(on_change_scene::<T>);
167 }
168
169 fn on_project_load_impl<T: GenericSingleton>(project: *mut aviutl2_sys::plugin2::PROJECT_FILE) {
170 {
171 let state = T::__get_singleton_state();
173 let guard = state.read().unwrap();
174 let plugin_state = guard.as_ref().expect("Plugin not initialized");
175 plugin_state
176 .is_edit_handle_ready
177 .store(true, std::sync::atomic::Ordering::SeqCst);
178 }
179 <T as GenericSingleton>::with_instance_mut(|instance| unsafe {
180 let mut project = ProjectFile::from_raw(project);
181 instance.on_project_load(&mut project);
182 });
183 }
184 extern "C" fn on_project_load<T: GenericSingleton>(
185 project: *mut aviutl2_sys::plugin2::PROJECT_FILE,
186 ) {
187 on_project_load_impl::<T>(project);
188 }
189 extern "C" fn on_project_load_unwind<T: GenericSingleton>(
190 project: *mut aviutl2_sys::plugin2::PROJECT_FILE,
191 ) {
192 if let Err(panic_info) =
193 crate::utils::catch_unwind_with_panic_info(|| on_project_load_impl::<T>(project))
194 {
195 tracing::error!("Panic occurred during on_project_load: {}", panic_info);
196 let _ = crate::logger::write_error_log(&panic_info);
197 }
198 }
199
200 fn on_project_save_impl<T: GenericSingleton>(project: *mut aviutl2_sys::plugin2::PROJECT_FILE) {
201 <T as GenericSingleton>::with_instance_mut(|instance| unsafe {
202 let mut project = ProjectFile::from_raw(project);
203 instance.on_project_save(&mut project);
204 });
205 }
206 extern "C" fn on_project_save<T: GenericSingleton>(
207 project: *mut aviutl2_sys::plugin2::PROJECT_FILE,
208 ) {
209 on_project_save_impl::<T>(project);
210 }
211 extern "C" fn on_project_save_unwind<T: GenericSingleton>(
212 project: *mut aviutl2_sys::plugin2::PROJECT_FILE,
213 ) {
214 if let Err(panic_info) =
215 crate::utils::catch_unwind_with_panic_info(|| on_project_save_impl::<T>(project))
216 {
217 tracing::error!("Panic occurred during on_project_save: {}", panic_info);
218 let _ = crate::logger::write_error_log(&panic_info);
219 }
220 }
221
222 fn on_clear_cache_impl<T: GenericSingleton>(
223 edit_section: *mut aviutl2_sys::plugin2::EDIT_SECTION,
224 ) {
225 <T as GenericSingleton>::with_instance_mut(|instance| unsafe {
226 let edit_section = crate::generic::EditSection::from_raw(edit_section);
227 instance.on_clear_cache(&edit_section);
228 });
229 }
230 extern "C" fn on_clear_cache<T: GenericSingleton>(
231 edit_section: *mut aviutl2_sys::plugin2::EDIT_SECTION,
232 ) {
233 on_clear_cache_impl::<T>(edit_section);
234 }
235 extern "C" fn on_clear_cache_unwind<T: GenericSingleton>(
236 edit_section: *mut aviutl2_sys::plugin2::EDIT_SECTION,
237 ) {
238 if let Err(panic_info) =
239 crate::utils::catch_unwind_with_panic_info(|| on_clear_cache_impl::<T>(edit_section))
240 {
241 tracing::error!("Panic occurred during on_clear_cache: {}", panic_info);
242 let _ = crate::logger::write_error_log(&panic_info);
243 }
244 }
245
246 fn on_change_scene_impl<T: GenericSingleton>(
247 edit_section: *mut aviutl2_sys::plugin2::EDIT_SECTION,
248 ) {
249 <T as GenericSingleton>::with_instance_mut(|instance| unsafe {
250 let edit_section = crate::generic::EditSection::from_raw(edit_section);
251 instance.on_change_scene(&edit_section);
252 });
253 }
254 extern "C" fn on_change_scene<T: GenericSingleton>(
255 edit_section: *mut aviutl2_sys::plugin2::EDIT_SECTION,
256 ) {
257 on_change_scene_impl::<T>(edit_section);
258 }
259 extern "C" fn on_change_scene_unwind<T: GenericSingleton>(
260 edit_section: *mut aviutl2_sys::plugin2::EDIT_SECTION,
261 ) {
262 if let Err(panic_info) =
263 crate::utils::catch_unwind_with_panic_info(|| on_change_scene_impl::<T>(edit_section))
264 {
265 tracing::error!("Panic occurred during on_change_scene: {}", panic_info);
266 let _ = crate::logger::write_error_log(&panic_info);
267 }
268 }
269}
270
271pub unsafe fn register_plugin<T: GenericSingleton>(
272 host: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
273) {
274 register_plugin_impl::<T>(host, false);
275}
276
277pub unsafe fn register_plugin_unwind<T: GenericSingleton>(
278 host: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
279) {
280 if let Err(panic_info) =
281 crate::utils::catch_unwind_with_panic_info(|| register_plugin_impl::<T>(host, true))
282 {
283 tracing::error!("Panic occurred during register_plugin: {}", panic_info);
284 let _ = crate::logger::write_error_log(&panic_info);
285 }
286}
287pub unsafe fn uninitialize_plugin<T: GenericSingleton>() {
288 let plugin_state = T::__get_singleton_state();
289 *plugin_state.write().unwrap() = None;
290}
291
292pub unsafe fn uninitialize_plugin_c_unwind<T: GenericSingleton>() {
293 match crate::utils::catch_unwind_with_panic_info(|| unsafe { uninitialize_plugin::<T>() }) {
294 Ok(()) => {}
295 Err(panic_info) => {
296 tracing::error!(
297 "Panic occurred during plugin uninitialization: {}",
298 panic_info
299 );
300 let _ = crate::logger::write_error_log(&panic_info);
301 }
302 }
303}
304
305#[macro_export]
311macro_rules! register_generic_plugin {
312 ($struct:ident, $($key:ident = $value:expr),* $(,)?) => {
313 $crate::__internal_module! {
314 #[unsafe(no_mangle)]
315 unsafe extern "C" fn RequiredVersion() -> u32 {
316 $crate::MINIMUM_AVIUTL2_VERSION.into()
317 }
318
319 #[unsafe(no_mangle)]
320 unsafe extern "C" fn InitializeLogger(logger: *mut $crate::sys::logger2::LOG_HANDLE) {
321 $crate::comptime_if::comptime_if! {
322 if unwind where (unwind = true, $( $key = $value ),* ) {
323 $crate::logger::__initialize_logger_unwind(logger)
324 } else {
325 $crate::logger::__initialize_logger(logger)
326 }
327 }
328 }
329
330 #[unsafe(no_mangle)]
331 unsafe extern "C" fn InitializeConfig(
332 config: *mut $crate::sys::config2::CONFIG_HANDLE
333 ) {
334 $crate::comptime_if::comptime_if! {
335 if unwind where (unwind = true, $( $key = $value ),* ) {
336 $crate::config::__initialize_config_handle_unwind(config)
337 } else {
338 $crate::config::__initialize_config_handle(config)
339 }
340 }
341 }
342
343 #[unsafe(no_mangle)]
344 unsafe extern "C" fn InitializePlugin(version: u32) -> bool {
345 unsafe {
346 $crate::comptime_if::comptime_if! {
347 if unwind where (unwind = true, $( $key = $value ),* ) {
348 $crate::generic::__bridge::initialize_plugin_c_unwind::<$struct>(version)
349 } else {
350 $crate::generic::__bridge::initialize_plugin_c::<$struct>(version)
351 }
352 }
353 }
354 }
355
356 #[unsafe(no_mangle)]
357 unsafe extern "C" fn GetCommonPluginTable() -> *mut $crate::sys::plugin2::COMMON_PLUGIN_TABLE {
358 $crate::comptime_if::comptime_if! {
359 if unwind where (unwind = true, $( $key = $value ),* ) {
360 unsafe { $crate::generic::__bridge::create_table_unwind::<$struct>() }
361 } else {
362 unsafe { $crate::generic::__bridge::create_table::<$struct>() }
363 }
364 }
365 }
366
367 #[unsafe(no_mangle)]
368 unsafe extern "C" fn UninitializePlugin() {
369 unsafe {
370 $crate::comptime_if::comptime_if! {
371 if unwind where (unwind = true, $( $key = $value ),* ) {
372 $crate::generic::__bridge::uninitialize_plugin_c_unwind::<$struct>()
373 } else {
374 $crate::generic::__bridge::uninitialize_plugin::<$struct>()
375 }
376 }
377 };
378 }
379
380 #[unsafe(no_mangle)]
381 unsafe extern "C" fn RegisterPlugin(host: *mut aviutl2::sys::plugin2::HOST_APP_TABLE) {
382 $crate::comptime_if::comptime_if! {
383 if unwind where (unwind = true, $( $key = $value ),* ) {
384 unsafe { $crate::generic::__bridge::register_plugin_unwind::<$struct>(host) };
385 } else {
386 unsafe { $crate::generic::__bridge::register_plugin::<$struct>(host) };
387 }
388 }
389 }
390 }
391 };
392 ($struct:ident, $($key:ident),* $(,)?) => {
393 $crate::register_generic_plugin!($struct, $( $key = true ),* );
394 };
395 ($struct:ident) => {
396 $crate::register_generic_plugin!($struct, );
397 };
398}