1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
//! 即使编译器既不提供 `Default` 也不允许具体化闭包 (即创建 `fn` 指针),但绝对没有捕获的任何可调用对象创建 `fn` 指针。
//!
//! 更具体地说,对于类似于闭包的类型是 "effectively `Default`":
//! * 它必须是 ZST (零大小类型) : 其中不包含任何信息,因此 `Default` 的返回值 (如果已实现) 是明确的
//! * 它必须是 `Copy`: 没有捕获的 "unique ZST tokens" 或任何其他会使随意重复值不合理的类似类型
//! * 结合 ZST 要求,这赋予了一种 "telecopy" 能力: 类似于 `Copy`,但不保留周围的值,而是在需要时 "reconstructing" 它 (因为它是 ZST 的 noop)
//! * 它必须*可证明*有人居住: 没有捕获的无人居住类型或任何其他无法由此抽象的用户构造的类型
//! * 证明是类似闭包的类型本身的值,从某种意义上说,ZST + `Copy` 使 "telecopy" 过程的 "seed" 成为可能
//! * 此要求是需要限制为特定用例的抽象的唯一原因: ZST + `Copy` 可以在 "attempted `::default()` call" 时间用 *atmost* a panic 进行检查,但这并不能保证可以正确创建该值,并尝试使用典型的 "proof ZST token" 方法再次导致 ZST + `Copy` 类型不能证明任何没有值的东西 (即
//! 与它试图证明居住的类型的 newtype 同构)
//!
//! 一旦 `const`- 泛型参数可以在其类型中具有类型参数,则可能存在针对一般问题的更灵活 (和更安全) 的解决方案:
//!
//! ```rust,ignore (needs future const-generics)
//! extern "C" fn ffi_wrapper<
//! A, R,
//! F: Fn(A) -> R,
//! const f: F, // <-- 这个 `const` 泛型还不允许
//! >(arg: A) -> R {
//! f(arg)
//! }
//! ```
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
//!
use std::mem;
// FIXME(eddyb) 除了 `const fn` 要求外,这可能是 `trait` impls。
macro_rules! define_reify_functions {
($(
fn $name:ident $(<$($param:ident),*>)?
for $(extern $abi:tt)? fn($($arg:ident: $arg_ty:ty),*) -> $ret_ty:ty;
)+) => {
$(pub const fn $name<
$($($param,)*)?
F: Fn($($arg_ty),*) -> $ret_ty + Copy
>(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty {
// FIXME(eddyb) 描述 `F` 类型 (例如
// 通过 `type_name::<F>`) 一旦在 `const fn` 中 panic 格式化成为可能。
assert!(mem::size_of::<F>() == 0, "selfless_reify: closure must be zero-sized");
$(extern $abi)? fn wrapper<
$($($param,)*)?
F: Fn($($arg_ty),*) -> $ret_ty + Copy
>($($arg: $arg_ty),*) -> $ret_ty {
let f = unsafe {
// SAFETY: `F` 满足 "out of thin air" 可重构性的所有标准 (请参见模块级文档注释)。
//
mem::MaybeUninit::<F>::uninit().assume_init()
};
f($($arg),*)
}
let _f_proof = f;
wrapper::<
$($($param,)*)?
F
>
})+
}
}
define_reify_functions! {
fn _reify_to_extern_c_fn_unary<A, R> for extern "C" fn(arg: A) -> R;
// HACK(eddyb) 此抽象与 `for<'a> fn(BridgeConfig<'a>) 一起使用
// -> T` 但这不适用于 `reify_to_extern_c_fn_unary` 因为 `fn` 指针类型是 "higher-ranked" (即
// the `for<'a>` binder).
// FIXME(eddyb) 尝试从 `BridgeConfig` 中删除生命周期,这会有所帮助。
//
fn reify_to_extern_c_fn_hrt_bridge<R> for extern "C" fn(bridge: super::BridgeConfig<'_>) -> R;
}