1#[allow(unused_imports)]
2use super::*;
3
4
5#[macro_export]
65macro_rules! extension {
66 {extern $symbol_initializer:ident $(, $symbol_finalizer:ident;
68 move $initializer:path, final $($finalizer:path)?)?;
69 gen $context_initializer:path, final $($context_finalizer:path)?;
70 } => {
71 const _: () = {
72 mod _flash_runtime_extension {
73 use super::*;
74 $crate::extension! {@Extern [$symbol_initializer $(, $symbol_finalizer, $initializer $(, $finalizer)?)?]}
75 #[allow(unsafe_op_in_unsafe_fn)]
76 unsafe extern "C" fn ctx_initializer (
77 ext_data: $crate::c::markers::FREData,
78 ctx_type: $crate::c::markers::FREStr,
79 ctx: $crate::c::markers::FREContext,
80 num_funcs_to_set: *mut u32,
81 funcs_to_set: *mut *const $crate::c::ffi::FRENamedFunction,
82 ) {
83 let context_initializer: $crate::function::ContextInitializer = $context_initializer;
84 $crate::context::CurrentContext::with_context_initializer(ext_data, ctx_type, &ctx, num_funcs_to_set, funcs_to_set, $context_initializer);
85 }
86 #[allow(unsafe_op_in_unsafe_fn)]
87 unsafe extern "C" fn ctx_finalizer (ctx: $crate::c::markers::FREContext) {
88 $crate::context::CurrentContext::with(&ctx, |ctx| {
89 $(
90 let context_finalizer: $crate::function::ContextFinalizer = $context_finalizer;
91 context_finalizer(ctx);
92 )?
93 let ctx = *(ctx as *const $crate::context::CurrentContext as *const $crate::context::ForeignContext);
94 let raw = ctx
95 .get_native_data()
96 .expect("Failed to retrieve native data from FFI.")
97 .expect("`ContextRegistry` is expected in native data but is missing.");
98 assert!(<::std::cell::RefCell<$crate::context::ContextRegistry> as $crate::data::Data>::ref_from(raw).is_ok());
99 $crate::data::drop_from(raw);
100 });
101
102 }
103 }
104 };
105 };
106 {@Extern [$symbol_initializer:ident, $symbol_finalizer:ident, $initializer:path $(, $finalizer:path)?]
108 } => {
109 #[allow(unsafe_op_in_unsafe_fn, non_snake_case)]
110 #[unsafe(no_mangle)]
111 pub unsafe extern "C" fn $symbol_initializer (
112 ext_data_to_set: *mut $crate::c::markers::FREData,
113 ctx_initializer_to_set: *mut $crate::c::ffi::FREContextInitializer,
114 ctx_finalizer_to_set: *mut $crate::c::ffi::FREContextFinalizer,
115 ) {
116 assert!(!ext_data_to_set.is_null());
117 assert!(!ctx_initializer_to_set.is_null());
118 assert!(!ctx_finalizer_to_set.is_null());
119 let initializer: $crate::function::Initializer = $initializer;
120 if let Some(ext_data) = initializer() {
121 let ext_data = ::std::sync::Arc::new(::std::sync::Mutex::new(ext_data));
122 *ext_data_to_set = <::std::sync::Arc<::std::sync::Mutex<Box<dyn ::std::any::Any>>> as $crate::data::Data>::into_raw(ext_data).as_ptr();
123 }
124 *ctx_initializer_to_set = ctx_initializer;
125 *ctx_finalizer_to_set = Some(ctx_finalizer);
126 $crate::extension! (@Hook);
127 }
128 #[allow(unsafe_op_in_unsafe_fn, non_snake_case)]
129 #[unsafe(no_mangle)]
130 pub unsafe extern "C" fn $symbol_finalizer (ext_data: $crate::c::markers::FREData) {
131 let ext_data = $crate::validated::NonNullFREData::new(ext_data)
132 .map(|raw| {
133 let arc_mutex_boxed = <::std::sync::Arc<::std::sync::Mutex<Box<dyn ::std::any::Any>>> as $crate::data::Data>::from_raw(raw);
134 let mutex = ::std::sync::Arc::try_unwrap(arc_mutex_boxed).expect("INVARIANT: No context exists.");
135 let boxed = mutex.into_inner().expect("Mutex poisoned.");
136 boxed
137 });
138 $(
139 let finalizer: $crate::function::Finalizer = $finalizer;
140 finalizer(ext_data);
141 )?
142 }
143 };
144 {@Extern [$symbol_initializer:ident]
146 } => {
147 #[allow(unsafe_op_in_unsafe_fn, non_snake_case)]
148 #[unsafe(no_mangle)]
149 pub unsafe extern "C" fn $symbol_initializer (
150 ext_data_to_set: *mut $crate::c::markers::FREData,
151 ctx_initializer_to_set: *mut $crate::c::ffi::FREContextInitializer,
152 ctx_finalizer_to_set: *mut $crate::c::ffi::FREContextFinalizer,
153 ) {
154 assert!(!ext_data_to_set.is_null());
155 assert!(!ctx_initializer_to_set.is_null());
156 assert!(!ctx_finalizer_to_set.is_null());
157 *ctx_initializer_to_set = ctx_initializer;
158 *ctx_finalizer_to_set = Some(ctx_finalizer);
159 $crate::extension! (@Hook);
160 }
161 };
162 (@Hook
164 ) => {
165 static INIT_HOOK: ::std::sync::Once = ::std::sync::Once::new();
166 INIT_HOOK.call_once(|| {
167 let default_hook = ::std::panic::take_hook();
168 ::std::panic::set_hook(Box::new(move |info| {
169 let payload = info.payload_as_str().unwrap_or_default();
170 let location = info.location()
171 .map(|l| format!("at {}:{}:{}", l.file(), l.line(), l.column()))
172 .unwrap_or_default();
173 let backtrace = ::std::backtrace::Backtrace::force_capture();
174 let s = format!("{payload}\n{location}\n{backtrace}");
175 $crate::_internal::LAST_PANIC_INFO.with(|i| {*i.borrow_mut() = Some(s);});
176 default_hook(info);
177 }));
178 });
179 }
180}
181
182
183#[macro_export]
238macro_rules! function {
239 {$name:ident ($($arguments:tt)+) $(-> $return_type:ty)? $body:block
241 } => {
242 #[allow(non_upper_case_globals)]
243 pub const $name: &'static $crate::function::FunctionImplementation = & $crate::function::FunctionImplementation::new(
244 $crate::function!(@Name $name), {
245 #[allow(unsafe_op_in_unsafe_fn)]
246 unsafe extern "C" fn abi(
247 ctx: $crate::c::markers::FREContext,
248 func_data: $crate::c::markers::FREData,
249 argc: u32,
250 argv: *const $crate::c::markers::FREObject,
251 ) -> $crate::c::markers::FREObject {
252 fn func <'a> (
253 ctx: &$crate::context::CurrentContext<'a>,
254 func_data: Option<&mut dyn ::std::any::Any>,
255 args: &[$crate::as3::Object<'a>],
256 ) -> $crate::as3::Object<'a> {
257 $crate::function! {@Parameters [ctx, func_data, args] $($arguments)+}
258 let r = ::std::panic::catch_unwind(|| -> $crate::function!(@Return $($return_type)?) {
259 $body
260 });
261 $crate::function! (@Unwind [ctx, r])
262 }
263 $crate::context::CurrentContext::with_method(&ctx, func_data, argc, argv, func)
264 }
265 abi},
266 );
267 };
268 ($name:ident use $func:path
270 ) => {
271 #[allow(non_upper_case_globals)]
272 pub const $name: &'static $crate::function::FunctionImplementation = & $crate::function::FunctionImplementation::new(
273 $crate::function!(@Name $name), {
274 #[allow(unsafe_op_in_unsafe_fn)]
275 unsafe extern "C" fn abi(
276 ctx: $crate::c::markers::FREContext,
277 func_data: $crate::c::markers::FREData,
278 argc: u32,
279 argv: *const $crate::c::markers::FREObject,
280 ) -> $crate::c::markers::FREObject {
281 let func: $crate::function::Function = $func;
282 let r = ::std::panic::catch_unwind(|| -> $crate::c::markers::FREObject {
283 $crate::context::CurrentContext::with_method(&ctx, func_data, argc, argv, func)
284 });
285 let ctx: $crate::context::CurrentContext = ::std::mem::transmute(ctx);
286 $crate::function! (@Unwind [&ctx, r])
287 }
288 abi},
289 );
290 };
291 (@Name $name:ident
293 ) => {
294 unsafe {
295 let s: &'static str = concat!(stringify!($name), "\0");
296 let s: &'static ::std::ffi::CStr = ::std::ffi::CStr::from_bytes_with_nul_unchecked(s.as_bytes());
297 let s = $crate::validated::UCStr::from_literal_unchecked(s);
298 s
299 }
300 };
301 (@Return $return_type:ty
303 ) => ($return_type);
304 (@Return
306 ) => (());
307 {@Parameters [$c:ident, $d:ident, $a:ident $(,)?]
309 $ctx:ident, $data:ident, $args:ident $(,)?
310 } => {
311 let $ctx: &$crate::context::CurrentContext<'a> = $c;
312 let $data: Option<&mut dyn ::std::any::Any> = $d;
313 let $args: &[$crate::as3::Object<'a>] = $a;
314 };
315 {@Parameters [$c:ident, $d:ident, $a:ident $(,)?]
317 $ctx:ident, $data:ident, _ $(,)?
318 } => {
319 $crate::function! {@Parameters [$c, $d, $a]
320 $ctx, $data, _args
321 }
322 };
323 {@Parameters [$c:ident, $d:ident, $a:ident $(,)?]
325 $ctx:ident, _, $args:ident $(,)?
326 } => {
327 $crate::function! {@Parameters [$c, $d, $a]
328 $ctx, _data, $args
329 }
330 };
331 {@Parameters [$c:ident, $d:ident, $a:ident $(,)?]
333 _, $data:ident, $args:ident $(,)?
334 } => {
335 $crate::function! {@Parameters [$c, $d, $a]
336 _ctx, $data, $args
337 }
338 };
339 {@Parameters [$c:ident, $d:ident, $a:ident $(,)?]
341 _, _, $args:ident $(,)?
342 } => {
343 $crate::function! {@Parameters [$c, $d, $a]
344 _ctx, _data, $args
345 }
346 };
347 {@Parameters [$c:ident, $d:ident, $a:ident $(,)?]
349 _, $data:ident, _ $(,)?
350 } => {
351 $crate::function! {@Parameters [$c, $d, $a]
352 _ctx, $data, _args
353 }
354 };
355 {@Parameters [$c:ident, $d:ident, $a:ident $(,)?]
357 $ctx:ident, _, _ $(,)?
358 } => {
359 $crate::function! {@Parameters [$c, $d, $a]
360 $ctx, _data, _args
361 }
362 };
363 {@Parameters [$c:ident, $d:ident, $a:ident $(,)?]
365 _, _, _ $(,)?
366 } => {
367 $crate::function! {@Parameters [$c, $d, $a]
368 _ctx, _data, _args
369 }
370 };
371 (@Unwind [$ctx:expr_2021, $catched:expr_2021]
373 ) => {
374 match $catched {
375 Ok(r) => r.into(),
376 Err(_) => {
377 let info = $crate::_internal::LAST_PANIC_INFO.with(|i| {i.borrow_mut().take()});
378 let msg = info.as_ref()
379 .map(|s|s.as_str())
380 .unwrap_or("Panic occurred but no details were captured.");
381 let err = $crate::as3::Error::new($ctx, Some(msg), i32::MIN);
382 err.set_name(Some($crate::as3::String::new($ctx, "Native Extension Panic Error")));
383 err.into()
384 },
385 }
386 }
387}
388