Rust插件库rinf的使用:高性能Rust与前端交互的桥梁,实现无缝通信与数据交换

Rust插件库rinf的使用:高性能Rust与前端交互的桥梁,实现无缝通信与数据交换

Rinf: Rust in Flutter

Pub Version Crate Version GitHub Stars Test App GitHub License

Rust用于原生业务逻辑,Flutter用于灵活美观的GUI

Preview

Rinf是一个框架,通过使用Flutter作为UI层来创建美观且高性能的跨平台Rust应用程序。只需将此框架添加到您的应用程序项目中,您就可以在Flutter中编写Rust!

文档

访问文档以了解有关使用此框架的所有信息。您还可以探索示例代码。

平台支持

Flutter可用的所有平台都经过测试和支持。具有挑战性的构建设置由该框架自动处理。

  • ✅ Linux:测试并支持
  • ✅ Android:测试并支持
  • ✅ Windows:测试并支持
  • ✅ macOS:测试并支持
  • ✅ iOS:测试并支持
  • ✅ Web:测试并支持
  • 🔄 eLinux:目前实验性

通信

以下是带有业务逻辑的Rust代码,随后是带有小部件的Dart代码。

MyMessage {
  current_number: 7,
  other_bool: true,
}
.send_signal_to_dart();
StreamBuilder(
  stream: MyMessage.rustSignalStream,
  builder: (context, snapshot) {
    final signalPack = snapshot.data;
    if (signalPack == null) {
      return Text('Nothing received yet');
    }
    final myMessage = signalPack.message;
    return Text(myMessage.currentNumber.toString());
  },
)

从Dart到Rust的消息传递也可以以类似的方式进行。

所有Dart类都是由Rinf以类型安全的方式生成的。您可以通过在Rust中使用可派生特征来定义消息模式。

好处

  • 真正简单:只需大约一两分钟即可完全设置您的应用程序。
  • 高效:所有通信仅通过原生FFI进行。没有Web视图、Web服务器、隐藏线程或不必要的内存复制可能导致性能开销。此设置充当Dart和Rust的非常薄的包装器。
  • 最小化:这不是一个笨重的框架,需要您安装许多依赖项并使用复杂的CLI命令。只需专注于使用您喜欢的Flutter和Rust库编写代码。
  • 事件驱动:异步系统对用户操作、消息或信号等事件做出反应。这允许高级并发、任务取消和非阻塞业务逻辑。
  • 可扩展:在Dart和Rust之间创建数百甚至数千个消息API感觉流畅且干净。此外,您可以灵活地使用任意数量的Rust库crate,可能包括您一直在使用的那些。
  • 高级接口:无需处理敏感的构建文件,无需担心内存安全。坚持使用您熟悉的Dart和Rust。
  • 维护良好:我们的自动化工作流程(包括构建测试)始终保持通过,这得益于主分支保护规则。此外,外部依赖项的数量尽可能保持较低,并且文档经过精心组织。
  • 方便的调试:所有调试功能都默认提供,无需处理浏览器或移动模拟器。此外,整个Rust逻辑在Dart的热重启时自动重新启动。
  • 可靠:每个组件都由庞大的社区支持,确保对未来安全的高度重视。您可以轻松地向团队保证稳定性,因为此框架的底层概念相当简单。

为什么使用Flutter?

虽然Rust是一种用于高性能原生编程的强大语言,但其构建图形用户界面的生态系统远未成熟。尽管Rust已经有一些GUI框架,但它们无法与Flutter提供的广泛支持和平滑的开发体验相提并论。Flutter是唯一一个从单一代码库编译到所有六个主要平台的框架。

Flutter是一个强大且多功能的框架,因其构建具有惊人用户界面的跨平台应用程序而广受欢迎。它提供声明式模式、美观的小部件、热重载、方便的调试工具以及开箱即用的专用用户界面包。

为什么使用Rust?

虽然Dart作为一种用于GUI应用程序的出色面向对象语言表现出色,但其非原生垃圾收集可能并不总是满足苛刻的性能要求,并且可能缺乏高级数据操作包。这就是Rust介入的地方,提供高达Dart40倍的速度优势,以及利用多个线程和各种完成工作的crate的能力。

Rust已经赢得了忠实的追随者,成为Stack Overflow上最受喜爱的编程语言。其原生性能,得益于零成本抽象哲学,确保了高生产力。许多开发人员预见Rust可能在未来取代C++。Rust的简单性、内存安全性、在各种场景下的卓越性能、充满活力的社区和强大的工具支持促成了其日益增长的受欢迎程度。

贡献

如果Rinf对您有帮助,请考虑给我们的GitHub存储库一个星标,并给我们的Pub包一个点赞。您还可以通过在网络上传播和分享此框架来支持我们。

我们感谢您对此项目开发的贡献!我们始终开放讨论和拉取请求,因此请不要犹豫,在我们的GitHub存储库上分享您的想法或意见。

GitHub contributors

完整示例代码:

// Rust端代码示例
use rinf::*;

// 定义消息结构
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MyMessage {
    pub current_number: i32,
    pub other_bool: bool,
}

impl Message for MyMessage {
    // 实现消息特征
}

// 业务逻辑处理
fn handle_business_logic() {
    // 创建消息实例
    let message = MyMessage {
        current_number: 7,
        other_bool: true,
    };
    
    // 发送信号到Dart
    message.send_signal_to_dart();
}

// 处理从Dart接收的消息
#[rinf::async_trait]
impl MessageHandler for MyMessage {
    async fn handle_message(&self) {
        // 处理接收到的消息
        println!("Received message: {:?}", self);
    }
}
// Dart端代码示例
import 'package:flutter/material.dart';
import 'package:rinf/rinf.dart';

// 在Flutter widget中使用
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Rinf Example'),
        ),
        body: StreamBuilder(
          stream: MyMessage.rustSignalStream,
          builder: (context, snapshot) {
            final signalPack = snapshot.data;
            if (signalPack == null) {
              return Text('Nothing received yet');
            }
            final myMessage = signalPack.message;
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('Current Number: ${myMessage.currentNumber}'),
                Text('Other Bool: ${myMessage.otherBool}'),
              ],
            );
          },
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            // 发送消息到Rust
            final message = MyMessage(
              currentNumber: 42,
              otherBool: false,
            );
            message.sendSignalToRust();
          },
          child: Icon(Icons.send),
        ),
      ),
    );
  }
}

1 回复

Rust插件库rinf:高性能Rust与前端交互的桥梁

介绍

rinf是一个专为Rust开发者设计的高性能插件库,旨在简化Rust与前端(如JavaScript/TypeScript)之间的通信和数据交换。通过提供简洁的API和高效的底层实现,rinf使得在Web应用、桌面应用或移动应用中集成Rust逻辑变得更加容易,同时保持出色的性能。

主要特性

  • 高性能通信:利用高效的序列化和反序列化机制,确保低延迟的数据交换
  • 跨平台支持:兼容多种前端框架和运行时环境(如WebAssembly、Node.js等)
  • 类型安全:通过Rust的强类型系统,减少运行时错误
  • 异步支持:原生支持异步操作,适合高并发场景

使用方法

安装

Cargo.toml中添加依赖:

[dependencies]
rinf = "0.5"

基本示例

以下是一个简单的示例,展示如何在Rust中定义函数,并通过rinf暴露给前端调用。

  1. 在Rust中定义函数
use rinf::prelude::*;

// 定义一个简单的加法函数
#[rinf::bridge]
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

// 定义一个异步函数,模拟耗时操作
#[rinf::bridge]
pub async fn fetch_data(url: String) -> Result<String, String> {
    // 模拟网络请求
    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
    Ok(format!("Data from {}", url))
}
  1. 在前端(JavaScript)中调用
// 假设rinf前端库已导入
import { callRust } from 'rinf-js';

// 调用同步函数
const result = await callRust('add', [5, 3]);
console.log(result); // 输出: 8

// 调用异步函数
try {
    const data = await callRust('fetch_data', ['https://example.com']);
    console.log(data); // 输出: "Data from https://example.com"
} catch (error) {
    console.error(error);
}

高级用法:复杂数据交换

rinf支持结构体和枚举类型的传递,确保类型安全。

  1. 在Rust中定义数据结构
use rinf::prelude::*;

#[rinf::bridge]
#[derive(Serialize, Deserialize)]
pub struct User {
    id: u64,
    name: String,
    email: String,
}

#[rinf::bridge]
pub fn create_user(name: String, email: String) -> User {
    User {
        id: 1, // 模拟ID生成
        name,
        email,
    }
}
  1. 在前端中调用
// 创建用户
const user = await callRust('create_user', ['Alice', 'alice@example.com']);
console.log(user); // 输出: { id: 1, name: "Alice", email: "alice@example.com" }

错误处理

rinf支持Result类型,方便错误传递。

#[rinf::bridge]
pub fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err("Division by zero".to_string())
    } else {
        Ok(a / b)
    }
}

在前端中处理错误:

try {
    const result = await callRust('divide', [10, 2]);
    console.log(result); // 输出: 5
} catch (error) {
    console.error(error); // 如果除零错误,输出: "Division by zero"
}

完整示例demo

Rust后端代码 (src/lib.rs)

use rinf::prelude::*;
use serde::{Deserialize, Serialize};

// 基本数学运算函数
#[rinf::bridge]
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

#[rinf::bridge]
pub fn subtract(a: i32, b: i32) -> i32 {
    a - b
}

#[rinf::bridge]
pub fn multiply(a: i32, b: i32) -> i32 {
    a * b
}

#[rinf::bridge]
pub fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err("Division by zero".to_string())
    } else {
        Ok(a / b)
    }
}

// 异步数据获取函数
#[rinf::bridge]
pub async fn fetch_data(url: String) -> Result<String, String> {
    // 模拟网络请求延迟
    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
    
    if url.contains("example") {
        Ok(format!("Fetched data from {}", url))
    } else {
        Err("Invalid URL".to_string())
    }
}

// 用户管理相关数据结构和函数
#[rinf::bridge]
#[derive(Serialize, Deserialize, Debug)]
pub struct User {
    pub id: u64,
    pub name: String,
    pub email: String,
    pub age: u8,
}

#[rinf::bridge]
#[derive(Serialize, Deserialize, Debug)]
pub enum UserStatus {
    Active,
    Inactive,
    Suspended,
}

#[rinf::bridge]
pub fn create_user(name: String, email: String, age: u8) -> User {
    User {
        id: generate_id(),
        name,
        email,
        age,
    }
}

#[rinf::bridge]
pub fn get_user_status(user: User) -> UserStatus {
    if user.age >= 18 {
        UserStatus::Active
    } else {
        UserStatus::Inactive
    }
}

// 工具函数
fn generate_id() -> u64 {
    use std::time::{SystemTime, UNIX_EPOCH};
    let start = SystemTime::now();
    let since_epoch = start.duration_since(UNIX_EPOCH).unwrap();
    since_epoch.as_secs()
}

// 批量处理函数
#[rinf::bridge]
pub fn process_numbers(numbers: Vec<i32>) -> Vec<i32> {
    numbers.into_iter().map(|x| x * 2).collect()
}

#[rinf::bridge]
pub async fn batch_process_urls(urls: Vec<String>) -> Vec<Result<String, String>> {
    let mut results = Vec::new();
    
    for url in urls {
        // 模拟每个URL的处理
        tokio::time::sleep(std::time::Duration::from_millis(100)).await;
        
        if url.starts_with("https://") {
            results.push(Ok(format!("Processed: {}", url)));
        } else {
            results.push(Err(format!("Invalid URL: {}", url)));
        }
    }
    
    results
}

前端JavaScript代码 (main.js)

import { callRust } from 'rinf-js';

// 数学运算示例
async function mathOperations() {
    try {
        console.log('=== 数学运算演示 ===');
        
        // 加法
        const sum = await callRust('add', [10, 5]);
        console.log('10 + 5 =', sum);
        
        // 减法
        const difference = await callRust('subtract', [20, 8]);
        console.log('20 - 8 =', difference);
        
        // 乘法
        const product = await callRust('multiply', [6, 7]);
        console.log('6 × 7 =', product);
        
        // 除法 - 正常情况
        const quotient = await callRust('divide', [15, 3]);
        console.log('15 ÷ 3 =', quotient);
        
        // 除法 - 错误情况
        try {
            await callRust('divide', [10, 0]);
        } catch (error) {
            console.log('10 ÷ 0 错误:', error);
        }
        
    } catch (error) {
        console.error('数学运算错误:', error);
    }
}

// 异步数据获取示例
async function dataFetching() {
    try {
        console.log('\n=== 数据获取演示 ===');
        
        // 成功的数据获取
        const data1 = await callRust('fetch_data', ['https://example.com/api']);
        console.log('数据获取成功:', data1);
        
        // 失败的数据获取
        try {
            await callRust('fetch_data', ['invalid-url']);
        } catch (error) {
            console.log('数据获取失败:', error);
        }
        
    } catch (error) {
        console.error('数据获取演示错误:', error);
    }
}

// 用户管理示例
async function userManagement() {
    try {
        console.log('\n=== 用户管理演示 ===');
        
        // 创建用户
        const user = await callRust('create_user', ['张三', 'zhangsan@example.com', 25]);
        console.log('创建的用户:', user);
        
        // 获取用户状态
        const status = await callRust('get_user_status', [user]);
        console.log('用户状态:', status);
        
        // 创建未成年用户
        const minorUser = await callRust('create_user', ['李四', 'lisi@example.com', 16]);
        const minorStatus = await callRust('get_user_status', [minorUser]);
        console.log('未成年用户状态:', minorStatus);
        
    } catch (error) {
        console.error('用户管理错误:', error);
    }
}

// 批量处理示例
async function batchProcessing() {
    try {
        console.log('\n=== 批量处理演示 ===');
        
        // 数字批量处理
        const numbers = [1, 2, 3, 4, 5];
        const processedNumbers = await callRust('process_numbers', [numbers]);
        console.log('原始数字:', numbers);
        console.log('处理后的数字:', processedNumbers);
        
        // URL批量处理
        const urls = [
            'https://api1.example.com',
            'https://api2.example.com',
            'invalid-url',
            'https://api3.example.com'
        ];
        
        console.log('开始批量处理URLs...');
        const urlResults = await callRust('batch_process_urls', [urls]);
        
        console.log('URL处理结果:');
        urlResults.forEach((result, index) => {
            if (result.ok) {
                console.log(`  ${urls[index]}: 成功 -`, result.value);
            } else {
                console.log(`  ${urls[index]}: 失败 -`, result.error);
            }
        });
        
    } catch (error) {
        console.error('批量处理错误:', error);
    }
}

// 主执行函数
async function main() {
    console.log('开始Rust与前端交互演示...\n');
    
    await mathOperations();
    await dataFetching();
    await userManagement();
    await batchProcessing();
    
    console.log('\n=== 演示完成 ===');
}

// 执行主函数
main().catch(console.error);

前端HTML模板 (index.html)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Rinf演示应用</title>
    <script type="module" src="./main.js"></script>
</head>
<body>
    <h1>Rinf Rust与前端交互演示</h1>
    <p>打开浏览器控制台查看演示结果</p>
</body>
</html>

Cargo.toml配置

[package]
name = "rinf-demo"
version = "0.1.0"
edition = "2021"

[dependencies]
rinf = "0.5"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }

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

总结

rinf通过简洁的API和高效的实现,为Rust与前端之间的通信提供了强大支持。无论是简单的函数调用还是复杂的数据交换,rinf都能确保类型安全和性能优化。通过上述完整示例,您可以快速开始使用rinf构建高性能的跨平台应用。

回到顶部