Deno调用Rust接口方法

Deno在1.13版本后,允许用户调用外部函数接口,外部函数接口FFI (Foreign Function Interface)由支持 C ABI的语言提供,如C/C++、Rust、Zig等。Deno使用Deno.dlopen导入外部函数库(Windows导入的是dll文件,Linux是so文件)。

一、Deno调用Rust函数接口

Rust代码

use std::ffi::{CStr, CString};
use deno_bindgen::deno_bindgen;


#[no_mangle]
pub extern "C" fn mul(a: isize, b: isize) -> isize {
    a * b
}

#[no_mangle]
pub extern "C" fn print_string(str_ptr: *const i8) -> () {
    let my_str: &str;
    unsafe {
        my_str = CStr::from_ptr(str_ptr).to_str().expect("this string could not be parsed");
        println!("this string passed to rust: {my_str}");
    }
}

//返回()对应TS的void
#[no_mangle]
pub extern "C" fn update_int_array(arr: *mut [i32; 2]) -> () {
    unsafe {
        let mut a = &mut *arr;
        println!("Rust :{} {}", a[0], a[1]);
        a[0] += 5;
        a[1] += 5;
    }
}

然后执行命令rustc --crate-type cdylib lib.rs,然后在debug文件夹里面就会有个dll文件

TypeScript代码


//dll文件的位置
const libName = "target\\debug\\deno_bindings.dll";
const dylib = Deno.dlopen(
    libName, {
        //mul对应Rust中的函数名
        //parameters对应Deno中参数类型
         //result对应Deno中的返回类型
        "mul": {
            parameters: ["isize", "isize"],
            result: "isize"
        },
        "print_string": {
            parameters: ["buffer"],
            result: "void"
        },
        "update_int_array": {
            parameters: ["buffer"],
            result: "void"
        }
    }
);

//两个数相乘返回一个结果
const result = dylib.symbols.mul(2, 3);
console.log(`Result from external Rust: ${result}`);

//传递字符串

const ts_str = "hello world! ,from TypeScript\0";//字符串为参数后面必须有 '\0'
const str_pointer = new TextEncoder().encode(ts_str);
dylib.symbols.print_string(str_pointer);

//修改整型数组
const int_arr = new Int32Array(2);
console.log("before TS :" + int_arr[0] + " ," + int_arr[1])
dylib.symbols.update_int_array(int_arr);
console.log("after TS :" + int_arr[0] + " ," + int_arr[1])


然后执行命令运行ts文件,deno run -A --unstable rustlib.ts

二、使用deno_bindgen库来简化编写

按照上面方法的来编写接口非常麻烦,因为Deno与Rust的数据类型不一样,FFI类型只有基本数据类型是和Rust相对应的,所以我们不能直接在Deno与Rust传递字符串、结构体、函数、对象、数组,在传递和返回这些参数的时候,我们需要手动计算不同数据类型的地址偏移,这样就很麻烦而且容易出错,不过好在有deno_bindgen库来帮助我们减小编写的难度。

deno_bindgen是一个Deno官方工具,它是用来在Deno与Rust之间生成胶水代码,方便我们编写Deno FFI库。

1、首先引入依赖

[package]
name = "libdeno_bindings"
version = "0.1.0"
edition = "2021"

[lib]
name = "libdeno_bindings"
crate-type = ["cdylib"]

[dependencies]
deno_bindgen = "0.8.1"
serde = { version = "1", features = ["derive"] }

2、然后在命令行安装Deno插件 

deno install -Afrq -n deno_bindgen https://deno.land/x/deno_bindgen/cli.ts

当输入deno_bindgen时候提示命令不存在,Deno的插件位置在用户目录\.deno\bin,请将这个目录添加到系统环境变量中

3、

//为需要传递的参数和使用的函数添加#[deno_bindgen]宏
#[deno_bindgen]
pub struct Point {
    a: i32,
    b: i32,
}
//Deno向Rust传递一个Point,对应ts类型{a:1,:b:2}
#[deno_bindgen]
pub fn add(point: Point) -> i32 {
    point.a + point.b
}
//从Rust返回一个结构体给Deno
#[deno_bindgen]
pub fn get_point() -> Point {
    Point {
        a: 4,
        b: 5,
    }
}
//在Rust中实现将字符串转大写
#[deno_bindgen]
pub fn convert(word: &str) -> String {
    word.to_uppercase()
}

#[deno_bindgen]
pub fn hello(msg: &str) -> String {
    println!("Rust收到: {msg}");
    "你好,来自Rust".to_string()
}

然后Rust编译生成dll文件以及bindings.json文件,然后命令行执行

deno_bindgen

这时候就会生成 bindings/bindings.ts文件

bindings.ts中生成相应的对象以及对应的函数接口,并将它们导出了,这样在别的地方我们只需要导入使用就好了,如果运行的时候Deno提示找不到相应的模块,请修改bindings.ts中dll的位置。

4、在新的ts文件中引入bindings.ts中的对象与函数

import {convert, get, get_string, add, hello, get_point} from "./bindings/bindings.ts";

console.log(add({a: 1, b: 2}))
console.log(get_point())
console.log(hello("Deno"))
console.log(convert("abcd"))

三、更多细节请查看官方文档和仓库

Foreign Function Interface | Deno Docs

https://github.com/denoland/deno_bindgen

如果Rust编译器提示类似"Type definition not found for `Input` identifier"的错误信息,请先删除bindings.json文件,再执行 deno_bindgen命令,然后重新编译。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值