使用 cxx<[T; N]> 将 Rust Vec

问题描述 投票:0回答:1

我正在使用 cxx 为 C++ 库编写一个 Rust 包装器。

此库中经常遇到的一种数据类型是可变大小的向量,其中每个元素都是固定大小的向量 - 例如包含 N 个三维点的 N 长度向量,每个点由 3 个双精度数组成。

查看 cxx 支持的绑定,似乎最明显的方法如下所示,将

Vec<[u64; 3]>
绑定到
rust::Vec<std::array<uint64_t, 3>>

// main.rs
include!("include/foo.h");
#[cxx::bridge]
pub mod ffi {

    unsafe extern "C++" {
        fn foo(x: Vec<[u64; 3]>);
    }
}
// foo.h
void foo(rust::Vec<std::array<uint64_t, 3>> x);

但是,这会产生以下错误:

  error[cxxbridge]: unsupported element type of Vec
     ┌─ src/main.rs:17:19
     │
  17 │         fn foo(x: Vec<[u64; 3]>);
     │                   ^^^^^^^^^^^^^ unsupported element type of Vec

解决方案确实有效,但并不理想:

  1. 创建共享结构,如

    Point3D
    ,并使用
    Vec<Point3D>
    。很烦人,因为我需要为每个变体提供一个新的结构。它也不干净,因为(在 3D 点的情况下)我已经有 Rust 和 C++ 中的数据类型用于表示点,所以这种类型实际上只在桥中使用。

  2. 展平为

    Vec<u64>
    ,然后展平为某种 Rust 类型。如果这是唯一的方法就好了,但感觉有点混乱。

在我开始为我需要在包装器中涵盖的所有各种方法重复此模式之前,我希望有一种更干净的方法。

c++ rust
1个回答
0
投票

不幸的是,C++ 不直接支持数组向量 (Vec<[u64; 3]>)。您可以通过定义封装固定大小数组的新包装类型来解决此限制。

#[cxx::bridge]
mod ffi {
    struct Point3D {
        data: [u64; 3],
    }

    extern "C++" {
        include!("include/foo.h");

        fn foo(x: Vec<Point3D>);
    }
}

impl From<[u64; 3]> for ffi::Point3D {
    fn from(arr: [u64; 3]) -> Self {
        ffi::Point3D { data: arr }
    }
}

impl From<ffi::Point3D> for [u64; 3] {
    fn from(point: ffi::Point3D) -> Self {
        point.data
    }
}

然后在C++中定义包装类型:

// foo.h
#include "rust/cxx.h"
#include <array>

struct Point3D {
    std::array<uint64_t, 3> data;
};

void foo(rust::Vec<Point3D> x);

现在实现C++函数:

// foo.cpp
#include "foo.h"
#include <iostream>

void foo(rust::Vec<Point3D> x) {
    for (const auto& point : x) {
        std::cout << "Point: [" << point.data[0] << ", " << point.data[1] << ", " << point.data[2] << "]" << std::endl;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.