#![cfg(all(feature = "proc_macros", feature = "default_jit_alloc"))]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "coverage", feature(coverage_attribute))]
#![allow(improper_ctypes_definitions)]
use closure_ffi::{bare_closure::bare_hrtb, BareFn, BareFnMut};
bare_hrtb! {
type MyFn = for<'a, 'b> extern "C" fn(&'a str, &'b str) -> &'a str;
}
struct MyStr(&'static str);
impl core::ops::Deref for MyStr {
type Target = str;
fn deref(&self) -> &Self::Target {
self.0
}
}
#[test]
fn test_basic_hrtb() {
let ignore_y = BareFn::<MyFn>::new(|x, _y| x);
fn do_test(bare_fn: for<'a, 'b> unsafe extern "C" fn(&'a str, &'b str) -> &'a str) {
let foo = MyStr("foo");
let result = {
let bar = MyStr("bar");
unsafe { bare_fn(&foo, &bar) }
};
assert_eq!(result, "foo");
}
do_test(ignore_y.bare().0);
}
bare_hrtb! {
type MyFnLt<'c> = for<'a> extern "C" fn(&'c str, &'a u32) -> &'a u32;
}
#[test]
fn test_non_static_hrtb() {
const STATIC_STR: &str = "xyz";
let owned_str1 = MyStr("foo");
let owned_str2 = MyStr("bar");
let mut ref_str: &str = &owned_str1;
let bare_closure = BareFnMut::<MyFnLt>::new(|x, y| {
ref_str = x;
y
});
let bare = bare_closure.bare();
assert_eq!(unsafe { bare(STATIC_STR, &0) }, &0);
{
let num = 1;
assert_eq!(unsafe { bare(&owned_str2, &num) }, &1);
}
drop(bare_closure);
assert_eq!(ref_str, &*owned_str2);
}
bare_hrtb!(
type MyGenericFn<T>
where
T: 'static + Clone,
= for<'a> extern "C" fn(&'a Option<T>) -> Option<&'a T>;
);
#[test]
fn test_generic_hrtb() {
let bare_closure = BareFn::<MyGenericFn<_>>::new(|opt| opt.as_ref());
fn do_test(bare_fn: unsafe extern "C" fn(&Option<u32>) -> Option<&u32>) {
assert_eq!(unsafe { bare_fn(&Some(123)) }, Some(&123));
}
do_test(bare_closure.bare().into());
}