#[macro_export]
macro_rules! scalar_callback {
($name:ident, |$info:ident, $input:ident, $output:ident| $body:block) => {
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $name(
$info: ::libduckdb_sys::duckdb_function_info,
$input: ::libduckdb_sys::duckdb_data_chunk,
$output: ::libduckdb_sys::duckdb_vector,
) {
let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $body));
if let Err(panic) = result {
let c_msg =
$crate::callback::message_to_c_string(&$crate::callback::panic_message(&panic));
unsafe {
::libduckdb_sys::duckdb_scalar_function_set_error($info, c_msg.as_ptr());
}
}
}
};
}
#[macro_export]
macro_rules! table_scan_callback {
($name:ident, |$info:ident, $output:ident| $body:block) => {
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $name(
$info: ::libduckdb_sys::duckdb_function_info,
$output: ::libduckdb_sys::duckdb_data_chunk,
) {
let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $body));
if let Err(panic) = result {
let c_msg =
$crate::callback::message_to_c_string(&$crate::callback::panic_message(&panic));
unsafe {
::libduckdb_sys::duckdb_function_set_error($info, c_msg.as_ptr());
::libduckdb_sys::duckdb_data_chunk_set_size($output, 0);
}
}
}
};
}
#[macro_export]
macro_rules! table_bind_callback {
($name:ident, |$info:ident| $body:block) => {
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $name($info: ::libduckdb_sys::duckdb_bind_info) {
let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $body));
if let Err(panic) = result {
let c_msg =
$crate::callback::message_to_c_string(&$crate::callback::panic_message(&panic));
unsafe {
::libduckdb_sys::duckdb_bind_set_error($info, c_msg.as_ptr());
}
}
}
};
}
#[macro_export]
macro_rules! table_init_callback {
($name:ident, |$info:ident| $body:block) => {
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $name($info: ::libduckdb_sys::duckdb_init_info) {
let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $body));
if let Err(panic) = result {
let c_msg =
$crate::callback::message_to_c_string(&$crate::callback::panic_message(&panic));
unsafe {
::libduckdb_sys::duckdb_init_set_error($info, c_msg.as_ptr());
}
}
}
};
}
#[macro_export]
macro_rules! aggregate_update_callback {
($name:ident, |$info:ident, $input:ident, $states:ident| $body:block) => {
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $name(
$info: ::libduckdb_sys::duckdb_function_info,
$input: ::libduckdb_sys::duckdb_data_chunk,
$states: *mut ::libduckdb_sys::duckdb_aggregate_state,
) {
let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $body));
if let Err(panic) = result {
let c_msg =
$crate::callback::message_to_c_string(&$crate::callback::panic_message(&panic));
unsafe {
::libduckdb_sys::duckdb_aggregate_function_set_error($info, c_msg.as_ptr());
}
}
}
};
}
#[macro_export]
macro_rules! aggregate_combine_callback {
($name:ident, |$info:ident, $source:ident, $target:ident, $count:ident| $body:block) => {
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $name(
$info: ::libduckdb_sys::duckdb_function_info,
$source: *mut ::libduckdb_sys::duckdb_aggregate_state,
$target: *mut ::libduckdb_sys::duckdb_aggregate_state,
$count: ::libduckdb_sys::idx_t,
) {
let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $body));
if let Err(panic) = result {
let c_msg =
$crate::callback::message_to_c_string(&$crate::callback::panic_message(&panic));
unsafe {
::libduckdb_sys::duckdb_aggregate_function_set_error($info, c_msg.as_ptr());
}
}
}
};
}
#[macro_export]
macro_rules! aggregate_finalize_callback {
($name:ident, |$info:ident, $source:ident, $result:ident, $count:ident, $offset:ident| $body:block) => {
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $name(
$info: ::libduckdb_sys::duckdb_function_info,
$source: *mut ::libduckdb_sys::duckdb_aggregate_state,
$result: ::libduckdb_sys::duckdb_vector,
$count: ::libduckdb_sys::idx_t,
$offset: ::libduckdb_sys::idx_t,
) {
let outcome = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $body));
if let Err(panic) = outcome {
let c_msg =
$crate::callback::message_to_c_string(&$crate::callback::panic_message(&panic));
unsafe {
::libduckdb_sys::duckdb_aggregate_function_set_error($info, c_msg.as_ptr());
}
}
}
};
}
#[macro_export]
macro_rules! aggregate_destroy_callback {
($name:ident, |$states:ident, $count:ident| $body:block) => {
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $name(
$states: *mut ::libduckdb_sys::duckdb_aggregate_state,
$count: ::libduckdb_sys::idx_t,
) {
let _ = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $body));
}
};
}
#[macro_export]
macro_rules! cast_callback {
($name:ident, |$info:ident, $count:ident, $input:ident, $output:ident| $body:block) => {
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $name(
$info: ::libduckdb_sys::duckdb_function_info,
$count: ::libduckdb_sys::idx_t,
$input: ::libduckdb_sys::duckdb_vector,
$output: ::libduckdb_sys::duckdb_vector,
) -> bool {
let outcome: ::std::result::Result<bool, _> =
::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $body));
match outcome {
::std::result::Result::Ok(ok) => ok,
::std::result::Result::Err(panic) => {
let c_msg = $crate::callback::message_to_c_string(
&$crate::callback::panic_message(&panic),
);
unsafe {
::libduckdb_sys::duckdb_cast_function_set_error($info, c_msg.as_ptr());
}
false
}
}
}
};
}
#[macro_export]
macro_rules! replacement_scan_callback {
($name:ident, |$info:ident, $table_name:ident, $data:ident| $body:block) => {
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $name(
$info: ::libduckdb_sys::duckdb_replacement_scan_info,
$table_name: *const ::std::os::raw::c_char,
$data: *mut ::std::os::raw::c_void,
) {
let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $body));
if let Err(panic) = result {
let c_msg =
$crate::callback::message_to_c_string(&$crate::callback::panic_message(&panic));
unsafe {
::libduckdb_sys::duckdb_replacement_scan_set_error($info, c_msg.as_ptr());
}
}
}
};
}
#[cfg(feature = "duckdb-1-5")]
#[macro_export]
macro_rules! copy_bind_callback {
($name:ident, |$info:ident| $body:block) => {
$crate::__copy_callback_impl!(
$name,
$info,
duckdb_copy_function_bind_info,
duckdb_copy_function_bind_set_error,
$body
);
};
}
#[cfg(feature = "duckdb-1-5")]
#[macro_export]
macro_rules! copy_global_init_callback {
($name:ident, |$info:ident| $body:block) => {
$crate::__copy_callback_impl!(
$name,
$info,
duckdb_copy_function_global_init_info,
duckdb_copy_function_global_init_set_error,
$body
);
};
}
#[cfg(feature = "duckdb-1-5")]
#[macro_export]
macro_rules! copy_finalize_callback {
($name:ident, |$info:ident| $body:block) => {
$crate::__copy_callback_impl!(
$name,
$info,
duckdb_copy_function_finalize_info,
duckdb_copy_function_finalize_set_error,
$body
);
};
}
#[cfg(feature = "duckdb-1-5")]
#[doc(hidden)]
#[macro_export]
macro_rules! __copy_callback_impl {
($name:ident, $info:ident, $info_ty:ident, $set_error:ident, $body:block) => {
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $name($info: ::libduckdb_sys::$info_ty) {
let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $body));
if let ::std::result::Result::Err(panic) = result {
let c_msg =
$crate::callback::message_to_c_string(&$crate::callback::panic_message(&panic));
unsafe {
::libduckdb_sys::$set_error($info, c_msg.as_ptr());
}
}
}
};
}
#[cfg(feature = "duckdb-1-5")]
#[macro_export]
macro_rules! copy_sink_callback {
($name:ident, |$info:ident, $chunk:ident| $body:block) => {
#[allow(unused_unsafe)]
pub unsafe extern "C" fn $name(
$info: ::libduckdb_sys::duckdb_copy_function_sink_info,
$chunk: ::libduckdb_sys::duckdb_data_chunk,
) {
let result = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| $body));
if let ::std::result::Result::Err(panic) = result {
let c_msg =
$crate::callback::message_to_c_string(&$crate::callback::panic_message(&panic));
unsafe {
::libduckdb_sys::duckdb_copy_function_sink_set_error($info, c_msg.as_ptr());
}
}
}
};
}
#[must_use]
pub fn panic_message(payload: &Box<dyn std::any::Any + Send>) -> String {
payload.downcast_ref::<&str>().map_or_else(
|| {
payload
.downcast_ref::<String>()
.map_or_else(|| String::from("<non-string panic payload>"), Clone::clone)
},
|s| (*s).to_string(),
)
}
#[must_use]
pub fn message_to_c_string(message: &str) -> std::ffi::CString {
std::ffi::CString::new(message.replace('\0', "?"))
.unwrap_or_else(|_| std::ffi::CString::default())
}