【问题标题】:How do I return complex structures to Python when using Rust FFI?使用 Rust FFI 时如何将复杂结构返回给 Python?
【发布时间】:2016-08-17 08:16:35
【问题描述】:

我希望用 Rust 重写 Python 项目的某些部分以加快速度。这个想法是使用 Rust 的 FFI 接口通过ctypes 连接到 Python。我每晚都在使用 Rust 1.10。

我需要将相当复杂的数组/结构返回给 Python。这不能正常工作。不幸的是,我在网上找不到任何此类问题的教程。

extern crate libc;
use libc::{c_int, c_char, size_t, c_float, c_double};
use std::ffi::{CStr, CString};
use std::str;
use std::vec::Vec;
use std::slice;
use std::mem;

#[repr(C)]
pub struct CPeak {
    // chemsc: *mut c_char, // adduct: c_char_p,
    mz_exp: c_float,
    mz_diff: c_float,
    intensity: c_float,
    resolution: c_float,
    noise: c_float,
    nb_frg: c_int,
    frgs: *mut CFrg,
}

#[repr(C)]
pub struct CFrg {
    mz_exp: c_float,
    mz_diff: c_float,
    intensity: c_float,
    resolution: c_float,
    noise: c_float,
}

#[no_mangle]
pub extern "C" fn standard_finder_get_standards(mut data: *mut *mut CPeak, mut len: *mut size_t) {
    // fill 'peaks' vector
    let peaks = find_standards(&standards.standards, "test.xml", 5.0, 10.0);

    // Copy contents of peaks (Rust structure) to CPeaks (C structure).
    // NOTE that CPeaks has a entry in the struct which is also a vector of
    // structs (frgs)
    let mut cpeaks: Vec<CPeak> = vec![];
    for peak in &peaks {

        // mk a vector frgs
        let mut frgs: Vec<CFrg> = vec![];
        if peak.frgs.len() > 0 {
            for frg in &peak.frgs {
                let f = CFrg {
                    mz_exp: frg.mz as c_float,
                    mz_diff: frg.mz_diff as c_float,
                    intensity: frg.intensity as c_float,
                    resolution: frg.resolution as c_float,
                    noise: frg.resolution as c_float,
                };
                frgs.push(f);
            }
        }
        frgs.shrink_to_fit();

        // mk a vector cpeaks
        cpeaks.push(CPeak {
            mz_exp: peak.mz as c_float,
            mz_diff: peak.mz_diff as c_float,
            intensity: peak.intensity as c_float,
            resolution: peak.resolution as c_float,
            noise: peak.resolution as c_float,
            nb_frg: peak.frgs.len() as c_int,
            frgs: frgs.as_ptr() as *mut CFrg, // <- add the frgs vector as c pointer (array)
        });
    }
    cpeaks.shrink_to_fit();
    unsafe {
        *data = cpeaks.as_ptr() as *mut CPeak;
        *len = cpeaks.len() as size_t;
    }
    mem::forget(cpeaks);
}

(Playground).

此代码采用 Rust 向量 (peaks: Vec&lt;Peak&gt;) 并将其内容复制到对应的 C 结构数组 (cpeaks: Vec&lt;CPeak&gt;)。在CPeak 中是另一个指向CFrg 数组的指针。 cpeaks 向量作为引用调用返回,以便为错误返回值留出空间。

当我尝试使用 Python 读取数据时,我遇到了两个问题:

  • cpeaks 的第一个条目为空或垃圾
  • CFrg 条目都是垃圾。

我猜问题是cpeaks 的生命周期,它的生命周期可能不够长,无法在 Python 中访问。但是,我不知道如何让它活着。我试过Boxing,但这没有帮助。

【问题讨论】:

  • 我认为您还需要在cpeaks.push(...); 行之后添加mem::forget(frgs);
  • @Dogbert:这是真的。然后它可以工作,但是类似于frgscpeaks 会被泄露,因为我无法释放它。

标签: python rust ffi


【解决方案1】:

您可以将 rust 代码称为 python 模块。

https://developers.redhat.com/blog/2017/11/16/speed-python-using-rust/

我不确定这是否是您想要的,但也许值得一看。

【讨论】:

    猜你喜欢
    • 2019-06-15
    • 1970-01-01
    • 1970-01-01
    • 2019-12-28
    • 1970-01-01
    • 2017-01-06
    • 1970-01-01
    • 1970-01-01
    • 2016-02-04
    相关资源
    最近更新 更多