rust - 使用 FFI 时如何创建 "C Blocks"?

标签 rust ffi

我在 OS X 上使用 CoreFoundation 框架,但我不知道如何在 Rust 中映射这个函数:

void CFRunLoopPerformBlock(CFRunLoopRef fl, CFTypeRef mode, void (^block)(void));

最后一个参数是 void(^block)(void) — 我如何创建这种类型的参数?

最佳答案

简短但可能有用的答案:有 block crate ,看起来它可以完成这项工作。

简短、无益的回答:据我所知,Rust 不支持 Apple 的 block 扩展。假设您想调用需要 block 的 API,则没有等效的 Rust 类型。

更长,略微无用的答案:根据我从 some Clang documentation on the Apple Block ABI 收集到的信息, void(^)(void) 将与常规指针大小相同。

因此,我的建议如下:将 block 视为不透明的指针大小的值。要调用一个,请用 C 编写一个函数来为您调用它。

以下未经测试(我没有 Mac),但至少应该让您朝着正确的方向前进。另外,我正在标记这个社区 wiki,这样任何可以测试它的人都可以在需要时修复它。

在 Rust 中:

// These are the "raw" representations involved.  I'm not using std::raw
// because that's not yet stabilised.
#[deriving(Copy, Clone)]
struct AppleBlock(*const ());

#[deriving(Copy, Clone)]
struct RustClosure(*const(), *const());

// Functions that we need to be written in C:
extern "C" {
    fn rust_closure_to_block(closure_blob: RustClosure) -> AppleBlock;
    fn block_release(block_blob: AppleBlock);
}

// The function that the C code will need.  Note that this is *specific* to
// FnMut() closures.  If you wanted to generalise this, you could write a
// generic version and pass a pointer to that to `rust_closure_to_block`.
extern "C" fn call_rust_closure(closure_blob: RustClosure) {
    let closure_ref: &FnMut() = unsafe { mem::transmute(closure_blob) };
    closure_ref();
}

// This is what you call in order to *temporarily* turn a closure into a
// block.  So, you'd use it as:
//
//     with_closure_as_block(
//         || do_stuff(),
//         |block| CFRunLoopPerformBlock(fl, mode, block)
//     );
fn with_closure_as_block<C, B, R>(closure: C, body: B) -> R
where C: FnMut(), B: FnOnce(block_blob) -> R {
    let closure_ref: &FnMut() = &closure;
    let closure_blob: RustClosure = unsafe { mem::transmute(closure_ref) };
    let block_blob = unsafe { rust_closure_to_block(closure_blob) };
    let r = body(block_blob);
    unsafe { block_release(block_blob) };
    r
}

在 C 中:

typedef struct AppleBlock {
    void *ptr;
} AppleBlock;

typedef struct RustClosure {
    void *ptr;
    void *vt;
} RustClosure;

void call_rust_closure(RustClosure closure_blob);

AppleBlock rust_closure_to_block(RustClosure closure_blob) {
    return (AppleBlock)Block_copy(^() {
        call_rust_closure(closure_blob);
    });
}

// I'm not using Block_release directly because I don't know if or how
// blocks change name mangling or calling.  You might be able to just
// use Block_release directly from Rust.
void block_release(AppleBlock block) {
    Block_release((void (^)(void))block);
}

关于rust - 使用 FFI 时如何创建 "C Blocks"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29693421/

相关文章:

json - 我可以使用类型来表示构造函数的至少一个参数应该是 Some 吗?

rust - 二元运算 `|` 不能应用于类型

rust - 尝试Bindgen教程时看到未找到bzlib.h

r - 从 R 调用 Prolog

multidimensional-array - 使用ndarray实现逐行操作

rust - Rust中的每个泛型是否都必须实现某些特征才能拥有 'methods'?

c - 通过bindgen从Rust到C的指针: first element is always zero

haskell - 如何使用 Haskell 和 FFI 与 C 枚举进行交互?

windows - 获取固定驱动器列表

python - 如何修复传递 int 数组时的段错误?