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