【问题标题】:Rust Polars - expected fn pointer, found opaque typeRust Polars - 预期的 fn 指针,发现不透明类型
【发布时间】:2022-08-17 04:43:32
【问题描述】:

我正在构建一个 raku 模块来使用 Rust Polars - 通过 Rust ffi。

通常它通过来回传递不透明的容器(SeriesC、ExprC 等)来工作。

我第一次通过 Expr .apply 函数看起来像这样(摘录):

use libc::c_char;
use libc::size_t;
use std::slice;
use std::ptr;
use std::ffi::*; //{CStr, CString,}
use polars::prelude::*;//{CsvReader, DataType, DataFrame, Series};
use polars::prelude::{Result as PolarResult};
use polars::lazy::dsl;
use polars::lazy::dsl::Expr;

pub struct SeriesC {
    se: Series,
}

impl SeriesC {
    fn new<T>(name: String, data: Vec::<T>) -> SeriesC
        where Series: NamedFrom<Vec<T>, [T]>
    {
        SeriesC {
            se: Series::new(&name, data),
        }
    }
// ...
}

type AppMap = extern fn(appmap: *mut SeriesC) -> SeriesC;

pub struct ExprC {
    pub inner: dsl::Expr,
}

impl ExprC {
    
    fn sum(&self) -> ExprC {
        self.clone().inner.clone().sum().into()
    }

// ... some more Exprs

    fn apply(&self, appmap: AMWrap) -> ExprC { 
        let o = GetOutput::from_type(DataType::UInt32);
        self.clone().inner.clone().apply(appmap, o).into()
    }
}

// ffi helper functions

#[no_mangle]
pub extern \"C\" fn ex_sum(ptr: *mut ExprC) -> *mut ExprC {
    let ex_c = unsafe {
        assert!(!ptr.is_null());
        &mut *ptr
    };

    Box::into_raw(Box::new(ex_c.sum()))
}

type AppMap = fn(*mut SeriesC) -> SeriesC;
type AMWrap = fn(Series) -> Result<Series>;

#[no_mangle]
pub extern \"C\" fn ex_apply(ptr: *mut ExprC, appmap: AppMap) -> *mut ExprC {
    let ex_c = check_ptr(ptr);


    fn c2s(se_c: SeriesC) -> Result<Series> {
        Ok(se_c.se.into_series())
    }

    fn s2c(series: Series) -> *mut SeriesC {
        let mut se_c = SeriesC::new::<u32>(\"dummy\".to_owned(), [].to_vec());
        se_c.se = series;
        Box::into_raw(Box::new(se_c))
    }

    fn compose<A, B, C, F, G>(f: F, g: G) -> impl Fn(A) -> C
    where
        F: Fn(B) -> C,
        G: Fn(A) -> B,
    {
        move |x| f(g(x))
    }
    let am_wrap_a = compose(appmap, s2c);
    let am_wrap_b = compose(c2s, am_wrap_a);

    Box::into_raw(Box::new(ex_c.apply(am_wrap_b)))
}

这种技术适用于 Expr\'s,例如 .sum()

对于.apply(),如您所见,我从 raku 端(未显示)得到一个回调,其类型为 AppMap 接受并返回 SeriesC 容器,我将其组合成 AMWrap 类型,该类型根据函数指针的要求接受并返回 Series传递给 Expr.apply 方法。

我已经设法将 Rust 错误减少到一个:

root@83471ed9aab4:~/raku-Dan-Polars/dan# cargo build
   Compiling dan v0.1.0 (/root/raku-Dan-Polars/dan)
error[E0308]: mismatched types
   --> src/lib.rs:881:39
    |
871 |     fn compose<A, B, C, F, G>(f: F, g: G) -> impl Fn(A) -> C
    |                                              --------------- the found opaque type
...
881 |     Box::into_raw(Box::new(ex_c.apply(am_wrap_b)))
    |                                       ^^^^^^^^^ expected fn pointer, found opaque type
    |
    = note: expected fn pointer `fn(polars::prelude::Series) -> std::result::Result<polars::prelude::Series, PolarsError>`
              found opaque type `impl Fn(polars::prelude::Series)-> std::result::Result<polars::prelude::Series, PolarsError>`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `dan` due to previous error

但是我无法理解如何将 compose 的返回类型连接到 AMWrap 类型。请问你能帮我吗?

这是 Cargo.toml 的完整性:

  1 [package]
  2 name = \"dan\"
  3 version = \"0.1.0\"
  4 edition = \"2021\"
  5 
  6 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
  7 
  8 [dependencies]
  9 libc = \"0.2.126\"
 10 polars = {version = \"0.22.1\", features = [\"lazy\"]}
 11 ffi-convert = \"0.5.0\"
 12 
 13 [lib]
 14 name = \"dan\"
 15 path = \"src/lib.rs\"
 16 crate-type = [\"cdylib\"]

    标签: rust rust-polars


    【解决方案1】:

    猜猜我让这个问题有点难以理解......几天后我接近答案了,就像这样:

     fn apply(&self, appmap: impl Fn(Series) -> Result<Series> + std::marker::Send + std::marker::Sync + 'static ) -> ExprC {
            let o = GetOutput::from_type(DataType::UInt32);
            self.clone().inner.clone().apply(appmap, o).into()
        }
    }
    
    type AppMap = fn(*mut SeriesC) -> SeriesC;
    //type AMWrap = fn(Series) -> Result<Series>;
    
    #[no_mangle]
    //iamerejh ... do the impl trick here too to address not FFI-safe warning??
    pub extern "C" fn ex_apply(ptr: *mut ExprC, appmap: AppMap) -> *mut ExprC {
        let ex_c = check_ptr(ptr);
    
    
        fn c2s(se_c: SeriesC) -> Result<Series> {
            Ok(se_c.se.into_series())
        }
    
        fn s2c(series: Series) -> *mut SeriesC {
            let mut se_c = SeriesC::new::<u32>("dummy".to_owned(), [].to_vec());
            se_c.se = series;
            Box::into_raw(Box::new(se_c))
        }
    
        //https://stackoverflow.com/questions/45786955/how-to-compose-functions-in-rust
        fn compose<A, B, C, F, G>(f: F, g: G) -> impl Fn(A) -> C
        where
            F: Fn(B) -> C,
            G: Fn(A) -> B,
        {
            move |x| f(g(x))
        }
        let am_wrap_a = compose(appmap, s2c);
        let am_wrap_b = compose(c2s, am_wrap_a);
    
        Box::into_raw(Box::new(ex_c.apply(am_wrap_b)))
    }
    

    最大的担忧是这会强制线程限制......并且我需要更改一些更高的设计方面,因此无法进行微调。

    希望这会帮助任何在这里绊倒的人!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-19
      • 1970-01-01
      • 2021-04-23
      • 2013-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多