aer*_*gnr 3 port native elixir rust
我正在编写教程,因为在任何地方都找不到通过端口在Elixir和Rust之间进行通信的简单示例。
我可以让Rustler工作,但这是NIF,而不是端口。
我的代码中缺少基本的东西。我不确定我是否在stdio中缺少基本的东西,或者是否还有其他东西,但是我尝试了很多不同的东西。
我可以使用Rust中的一个非常基本的程序来进行端口通信:
use std::env;
fn main() {
println!("hello world!");
}
Run Code Online (Sandbox Code Playgroud)
我可以通过运行以下端口来将其加入我的iex -S组合中:
defmodule PortExample do
def test() do
port = Port.open({:spawn_executable, "_build/dev/rustler_crates/portexample/debug/portexample"}, [:binary])
Port.info(port)
port
end
Run Code Online (Sandbox Code Playgroud)
这是该iex的样子:
defmodule PortExample do
def test() do
port = Port.open({:spawn_executable, "_build/dev/rustler_crates/portexample/debug/portexample"}, [:binary])
Port.info(port)
port
end
Run Code Online (Sandbox Code Playgroud)
我可以使用瓷器库调用执行相同的操作:
alias Porcelain.Result
def porcelain() do
result = Porcelain.exec("_build/dev/rustler_crates/portexample/debug/portexample",["hello", "world"])
IO.inspect result.out
end
Run Code Online (Sandbox Code Playgroud)
对应的IEX:
Interactive Elixir (1.4.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> PortExample.test()
#Port<0.9420>
iex(2)> flush()
{#Port<0.9420>, {:data, "hello world!\n"}}
:ok
iex(3)>
Run Code Online (Sandbox Code Playgroud)
但是,一旦我开始使用具有某种形式的输入/输出的Rust库,事情就会开始崩溃。
例如,Rust代码:
alias Porcelain.Result
def porcelain() do
result = Porcelain.exec("_build/dev/rustler_crates/portexample/debug/portexample",["hello", "world"])
IO.inspect result.out
end
Run Code Online (Sandbox Code Playgroud)
我可以将其编译并在命令行中运行:
iex(3)> PortExample.porcelain()
"hello world!\n"
"hello world!\n"
iex(4)>
Run Code Online (Sandbox Code Playgroud)
但是,当我从Elixir端口调用它时:
use std::io::{self, Write, Read};
fn main() {
let mut input = String::new();
let mut output = String::new();
for i in 0..2 {
match io::stdin().read_line(&mut input) {
Ok(n) => {
println!("input: {}", input.trim());
io::stdout().flush();
}
Err(error) => println!("error: {}", error),
}
}
}
Run Code Online (Sandbox Code Playgroud)
我一点也没有得到任何数据!但是,该Port.info(port)呼叫显示其接收到15个字节。它只是没有发布过而已将任何东西返回到端口。我一直在尝试阅读其他代码,并且我认为我所做的事情足够相似,以至于它应该可以工作,但事实并非如此。
我以为:也许缓冲区没有刷新?所以我在Rust中刷新缓冲区。我以为:也许循环正在挂起,所以我只将其限制为几遍。当我尝试通过瓷器调用运行相同的代码时,它挂起了。
您正在读取Rust代码中的输入行,该行将一直读取到\r\n或为止\n,但您不是从Elixir发送换行符。如果您更改所有Port.command呼叫以\n在消息后添加a ,则该方法有效:
iex(1)> port = Port.open({:spawn_executable, "a"}, [:binary])
#Port<0.1229>
iex(2)> Port.command(port, "hello")
true
iex(3)> flush()
:ok
iex(4)> Port.command(port, "hello\n")
true
iex(5)> flush()
{#Port<0.1229>, {:data, "input: hellohello\n"}}
:ok
Run Code Online (Sandbox Code Playgroud)