20 个版本 (8 个破坏性更新)
0.11.0 | 2023年9月15日 |
---|---|
0.9.6 | 2023年7月21日 |
0.6.3 | 2022年5月20日 |
0.6.2 | 2022年3月25日 |
0.3.3 | 2021年11月17日 |
168 在 开发工具 中排名
46,163 每月下载量
115KB
3K SLoC
Membrane
开发环境
- Rust
- Dart
- libclang(用于生成绑定)
- Linux
apt-get安装 libclang-dev
- MacOS
brew安装 llvm
- Linux
在 Linux 上,ffigen 会查找位于 /usr/lib/llvm-11/lib/libclang.so
的 libclang,因此你可能需要将其链接到特定版本的库:ln -s /usr/lib/llvm-11/lib/libclang.so.1 /usr/lib/llvm-11/lib/libclang.so
。
使用方法
查看 示例 目录中的可运行示例。
在你的 crate 的 lib.rs
中添加一个 RUNTIME
静态变量,该变量将存在于整个程序的生命周期中。 RUNTIME
必须持有 membrane::App<Runtime>
实例,其中 Runtime
为你希望使用的任何异步框架实现了 membrane::Interface
特性。在我们的示例中,我们使用 tokio
来提供运行时行为,欢迎你复制它
use membrane::runtime::{App, Interface, AbortHandle};
pub struct Runtime(tokio::runtime::Runtime);
impl Interface for Runtime {
fn spawn<F>(&self, future: F) -> AbortHandle
where
F: std::future::Future + Send + 'static,
F::Output: Send + 'static,
{
let handle = self.0.spawn(future);
AbortHandle {
abort: Box::new(move || handle.abort()),
}
}
fn spawn_blocking<F, R>(&self, future: F) -> AbortHandle
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
let handle = self.0.spawn_blocking(future);
AbortHandle {
abort: Box::new(move || handle.abort()),
}
}
}
static RUNTIME: App<Runtime> = App::new(|| {
Runtime(
tokio::runtime::Builder::new_multi_thread()
.worker_threads(2)
.thread_name("libexample")
.build()
.unwrap()
)
});
然后编写一些带有 #[async_dart]
宏注释的代码。这里不需要使用 C 类型,只需使用 Rust 的 String
、i64
、f64
、bool
、结构体或枚举(或使用 Option
)即可。函数可以放在程序中的任何位置,并可能返回一个异步的 Result<T, E>
或一个 impl Stream<Item = Result<T, E>>
use membrane::async_dart;
use tokio_stream::Stream;
use crate::data;
#[async_dart(namespace = "accounts")]
pub fn contacts() -> impl Stream<Item = Result<data::Contact, data::Error>> {
futures::stream::iter(vec![Ok(Default::default())])
}
#[async_dart(namespace = "accounts")]
pub async fn contact(id: String) -> Result<data::Contact, data::Error> {
Ok(data::Contact {
id: id.parse().unwrap(),
..Default::default()
})
}
现在您已经准备好生成 Dart 包了。请注意,这段代码应该放在 bin/generator.rs
或类似的文件中,并使用 cargo run
或构建任务来运行,而不是在 build.rs
中(该文件仅在编译前运行)。
fn main() {
// if nothing else in this generator.rs references lib.rs then
// at least call a dummy function so lib.rs doesn't get optimized away
example::load();
let mut project = membrane::Membrane::new();
project
// name the output pub directory
.package_destination_dir("../dart_example")
// the pub package name, if different than the directory
.package_name("example")
// give the basename of the .so or .dylib that your Rust program provides
.using_lib("libexample")
// use Dart enums instead of class enums
.with_c_style_enums(true)
.create_pub_package()
.write_api()
.write_c_headers()
.write_bindings();
}
如果一切按计划进行,您现在可以从 Dart 中调用 Rust:
cd example
cargo run
cargo build
cd ../dart_example
cp ../example/target/debug/libexample.dylib .
dart --enable-asserts run
(--enable-asserts
启用生成类中的漂亮打印 toString()
)
import 'package:dart_example/accounts.dart';
void main(List<String> arguments) async {
var accounts = AccountsApi();
print(await accounts.contact(id: "1"));
}
如果在 Linux 上遇到无法加载 libexample.so
的错误,请将 pub 包的路径添加到 LD_LIBRARY_PATH
。
依赖项
~7–14MB
~158K SLoC