#[allow(unused_imports)]
use super::*;
#[macro_export]
macro_rules! extension {
{ extern $symbol_initializer:ident $(, $symbol_finalizer:ident;
move $initializer:path, final $($finalizer:path)?)?;
gen $context_initializer:path, final $($context_finalizer:path)?;
} => {
const _: () = {
mod _flash_runtime_extension {
use super::*;
$crate::extension! {@Extern [$symbol_initializer $(, $symbol_finalizer, $initializer $(, $finalizer)?)?]}
#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn ctx_initializer (
ext_data: $crate::c::markers::FREData,
ctx_type: $crate::c::markers::FREStr,
ctx: $crate::c::markers::FREContext,
num_funcs_to_set: *mut u32,
funcs_to_set: *mut *const $crate::c::ffi::FRENamedFunction,
) {
let context_initializer: $crate::function::ContextInitializer = $context_initializer;
$crate::context::FlashRuntime::with_context_initializer(ext_data, ctx_type, &ctx, num_funcs_to_set, funcs_to_set, $context_initializer);
}
#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn ctx_finalizer (ctx: $crate::c::markers::FREContext) {
$crate::context::FlashRuntime::with(&ctx, |frt| {
$(
let context_finalizer: $crate::function::ContextFinalizer = $context_finalizer;
context_finalizer(frt);
)?
let raw = $crate::validated::NonNullFREData::new(frt.current_context().get_native_data().expect("Failed to retrieve native data from FFI.")).expect("`ContextRegistry` is expected in native data but is missing.");
assert!(<$crate::context::ContextRegistry as $crate::data::Data>::ref_from(raw).is_ok());
$crate::data::drop_from(raw);
});
}
}
};
};
{ @Extern [$symbol_initializer:ident, $symbol_finalizer:ident, $initializer:path $(, $finalizer:path)?]
} => {
#[allow(unsafe_op_in_unsafe_fn, non_snake_case)]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn $symbol_initializer (
ext_data_to_set: *mut $crate::c::markers::FREData,
ctx_initializer_to_set: *mut $crate::c::ffi::FREContextInitializer,
ctx_finalizer_to_set: *mut $crate::c::ffi::FREContextFinalizer,
) {
assert!(!ext_data_to_set.is_null());
assert!(!ctx_initializer_to_set.is_null());
assert!(!ctx_finalizer_to_set.is_null());
let initializer: $crate::function::Initializer = $initializer;
if let Some(ext_data) = initializer() {
*ext_data_to_set = $crate::data::into_raw(ext_data).as_ptr();
}
*ctx_initializer_to_set = ctx_initializer;
*ctx_finalizer_to_set = Some(ctx_finalizer);
$crate::extension! (@Hook);
}
#[allow(unsafe_op_in_unsafe_fn, non_snake_case)]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn $symbol_finalizer (ext_data: $crate::c::markers::FREData) {
let ext_data = $crate::validated::NonNullFREData::new(ext_data)
.map(|raw| $crate::data::from_raw(raw));
$(
let finalizer: $crate::function::Finalizer = $finalizer;
finalizer(ext_data);
)?
}
};
{ @Extern [$symbol_initializer:ident]
} => {
#[allow(unsafe_op_in_unsafe_fn, non_snake_case)]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn $symbol_initializer (
ext_data_to_set: *mut $crate::c::markers::FREData,
ctx_initializer_to_set: *mut $crate::c::ffi::FREContextInitializer,
ctx_finalizer_to_set: *mut $crate::c::ffi::FREContextFinalizer,
) {
assert!(!ext_data_to_set.is_null());
assert!(!ctx_initializer_to_set.is_null());
assert!(!ctx_finalizer_to_set.is_null());
*ctx_initializer_to_set = ctx_initializer;
*ctx_finalizer_to_set = Some(ctx_finalizer);
$crate::extension! (@Hook);
}
};
( @Hook
) => {
static INIT_HOOK: ::std::sync::Once = ::std::sync::Once::new();
INIT_HOOK.call_once(|| {
let default_hook = ::std::panic::take_hook();
::std::panic::set_hook(Box::new(move |info| {
let payload = info.payload_as_str().unwrap_or_default();
let location = info.location()
.map(|l| format!("at {}:{}:{}", l.file(), l.line(), l.column()))
.unwrap_or_default();
let backtrace = ::std::backtrace::Backtrace::force_capture();
let s = format!("{payload}\n{location}\n{backtrace}");
$crate::_internal::LAST_PANIC_INFO.with(|i| {*i.borrow_mut() = Some(s);});
default_hook(info);
}));
});
}
}
#[macro_export]
macro_rules! function {
{ $name:ident ($($arguments:tt)+) $(-> $return_type:ty)? $body:block
} => {
#[allow(non_upper_case_globals)]
pub const $name: &'static $crate::function::FunctionDefinition = & $crate::function::FunctionDefinition::new(
$crate::function!(@Name $name), {
#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn abi(
ctx: $crate::c::markers::FREContext,
func_data: $crate::c::markers::FREData,
argc: u32,
argv: *const $crate::c::markers::FREObject,
) -> $crate::c::markers::FREObject {
fn func <'a> (
frt: &$crate::context::FlashRuntime<'a>,
func_data: Option<&mut dyn ::std::any::Any>,
args: &[$crate::types::Object<'a>],
) -> $crate::types::Object<'a> {
$crate::function! {@Parameters [frt, func_data, args] $($arguments)+}
let r = ::std::panic::catch_unwind(|| -> $crate::function!(@Return $($return_type)?) {
$body
});
$crate::function! (@Unwind [frt, r])
}
$crate::context::FlashRuntime::with_method(&ctx, func_data, argc, argv, func)
}
abi},
);
};
( $name:ident use $func:path
) => {
#[allow(non_upper_case_globals)]
pub const $name: &'static $crate::function::FunctionDefinition = & $crate::function::FunctionDefinition::new(
$crate::function!(@Name $name), {
#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn abi(
ctx: $crate::c::markers::FREContext,
func_data: $crate::c::markers::FREData,
argc: u32,
argv: *const $crate::c::markers::FREObject,
) -> $crate::c::markers::FREObject {
let func: $crate::function::Function = $func;
let r = ::std::panic::catch_unwind(|| -> $crate::c::markers::FREObject {
$crate::context::FlashRuntime::with_method(&ctx, func_data, argc, argv, func)
});
let frt: $crate::context::FlashRuntime = ::std::mem::transmute(ctx);
$crate::function! (@Unwind [&frt, r])
}
abi},
);
};
( @Name $name:ident
) => {
unsafe {
let s: &'static str = concat!(stringify!($name), "\0");
let s: &'static ::std::ffi::CStr = ::std::ffi::CStr::from_bytes_with_nul_unchecked(s.as_bytes());
let s = $crate::validated::UCStr::from_literal_unchecked(s);
s
}
};
( @Return $return_type:ty
) => ($return_type);
( @Return
) => (());
{ @Parameters [$f:ident, $d:ident, $a:ident $(,)?]
$frt:ident, $data:ident, $args:ident $(,)?
} => {
let $frt: &$crate::context::FlashRuntime<'a> = $f;
let $data: Option<&mut dyn ::std::any::Any> = $d;
let $args: &[$crate::types::Object<'a>] = $a;
};
{ @Parameters [$f:ident, $d:ident, $a:ident $(,)?]
$frt:ident, $data:ident, _ $(,)?
} => {
$crate::function! {@Parameters [$f, $d, $a]
$frt, $data, _args
}
};
{ @Parameters [$f:ident, $d:ident, $a:ident $(,)?]
$frt:ident, _, $args:ident $(,)?
} => {
$crate::function! {@Parameters [$f, $d, $a]
$frt, _data, $args
}
};
{ @Parameters [$f:ident, $d:ident, $a:ident $(,)?]
_, $data:ident, $args:ident $(,)?
} => {
$crate::function! {@Parameters [$f, $d, $a]
_frt, $data, $args
}
};
{ @Parameters [$f:ident, $d:ident, $a:ident $(,)?]
_, _, $args:ident $(,)?
} => {
$crate::function! {@Parameters [$f, $d, $a]
_frt, _data, $args
}
};
{ @Parameters [$f:ident, $d:ident, $a:ident $(,)?]
_, $data:ident, _ $(,)?
} => {
$crate::function! {@Parameters [$f, $d, $a]
_frt, $data, _args
}
};
{ @Parameters [$f:ident, $d:ident, $a:ident $(,)?]
$frt:ident, _, _ $(,)?
} => {
$crate::function! {@Parameters [$f, $d, $a]
$frt, _data, _args
}
};
{ @Parameters [$f:ident, $d:ident, $a:ident $(,)?]
_, _, _ $(,)?
} => {
$crate::function! {@Parameters [$f, $d, $a]
_frt, _data, _args
}
};
( @Unwind [$frt:expr_2021, $catched:expr_2021]
) => {
match $catched {
Ok(r) => r.into(),
Err(_) => {
let info = $crate::_internal::LAST_PANIC_INFO.with(|i| {i.borrow_mut().take()});
let msg = info.as_ref()
.map(|s|s.as_str())
.unwrap_or("Panic occurred but no details were captured.");
let err = $crate::types::ErrorObject::new($frt, Some(msg), i32::MIN);
err.set_name(Some($crate::types::StringObject::new($frt, "Native Extension Panic Error")));
err.into()
},
}
}
}