在C++类中包装Rust结构

goo*_*goo 5 rust

我想在C++类中包装一个Rust结构.

锈:

#[repr(C)]
pub struct RustStruct {
  num: i32,
  // other members..
}

pub extern "C" fn update(rust_struct: *mut RustStruct) {
  (*rust_struct).num = 1i32;
}

extern "C" {
  void update(void*);
}
Run Code Online (Sandbox Code Playgroud)

C++:

class Wrapper {
  public:
    Wrapper();
    // ..

  private:
    void* rustStruct;
    // ..
};

Wrapper::Wrapper() {
  update(rustStruct); // crash
}

int main() {
  std::cout << "Testing..";
}
Run Code Online (Sandbox Code Playgroud)

我理解为什么这不起作用.我的问题是:我怎样才能实现我基本上要做的事情(在c ++类中包装一个rust结构)?

Mat*_* M. 10

您的答案中有多个FFI概念的混合,所以首先让我建议您阅读参考.

有两种方法可以达到你想要的效果,你可以:

  • 使用POD struct(普通旧数据),又称C兼容结构
  • 使用不透明指针(void*在C中)

像你一样混合它们是没有意义的.


选哪个?

这两种解决方案都有优点和缺点,它基本上是表达性与性能权衡.

一方面,不透明指针更具表现力:它们可以指向任何Rust类型.然而:

  • 他们需要动态内存分配
  • 它们需要被Rust函数操作(所以总是间接地从C或C++)

另一方面,POD结构不需要其中任何一个,但它们仅限于Rust中可表达的类型的子集.


如何使用POD?

实际上,这是最简单的,所以让我们从它开始吧!

在Rust:

#[repr(C)]
pub struct RustStruct {
    num: i32,
    // other members, also PODs!
}
Run Code Online (Sandbox Code Playgroud)

在C++中

struct RustStruct {
    int32_t num;
    // other members, also with Standard Layout
    // http://en.cppreference.com/w/cpp/types/is_standard_layout
};

class Wrapper {
public:
private:
    RustStruct rustStruct;
};
Run Code Online (Sandbox Code Playgroud)

请注意,我刚刚在这里提出了你的问题stricto censu,你实际上可以在一个C++类中合并这两个:

class RustStruct {
public:
private:
    int32_t num;
    // other members, also with Standard Layout
    // http://en.cppreference.com/w/cpp/types/is_standard_layout
};
Run Code Online (Sandbox Code Playgroud)

只是避免virtual方法.


如何使用不透明指针?

这变得更棘手:

  • 只有Rust代码可以正确创建/复制/破坏类型
  • 小心漏水......

所以,我们需要在Rust中实现很多功能:

#![feature(box_raw, box_syntax)]
use std::boxed;

pub struct RustStruct {
    num: i32,
    // other members, anything goes
}

pub extern "C" fn createRustStruct() -> *mut RustStruct {
    boxed::into_raw(box RustStruct::new())
}

pub extern "C" fn destroyRustStruct(o: *mut RustStruct) {
    boxed::from_raw(o);
}
Run Code Online (Sandbox Code Playgroud)

好吧......现在开始使用C++:

struct RustStruct;

RustStruct* createRustStruct();
void destroyRustStruct(RustStruct*);

class Wrapper {
public:
    Wrapper(): rustStruct(RustStructPtr(createRustStruct())) {}

private:
    struct Deleter {
        void operator()(RustStruct* rs) const {
            destroyRustStruct(rs);
        }
    };

    typedef std::unique_ptr<RustStruct, Deleter> RustStructPtr;

    RustStructPtr rustStruct;
}; // class Wrapper
Run Code Online (Sandbox Code Playgroud)

所以,是的,更多涉及,并且Wrapper也不可复制(复制也必须委托给Rust).无论如何,这应该让你开始!

注意:如果你有很多不透明的指针需要包装,那么将复制/销毁函数作为模板参数的模板化C++类可以减轻很多锅炉板块.