I'm trying to call a Dyon built-in function (sin) from Rust:
use dyon::{Module, Runtime, Variable};
use std::sync::Arc;
fn main() {
let mut dyon_runtime = Runtime::new();
let module = Module::new();
let dyon_module = Arc::new(module);
let v = dyon_runtime.call_str_ret("sin", &[Variable::f64(0.0)], &dyon_module);
match v {
Err(e) => {
eprintln!("Error: {:?}", e);
}
Ok(v) => {
println!("Called sin - result {:?}", v);
}
};
}
However, I get
Error: "Could not find function `sin`"
What do I need to do to correctly call this function?
I can't explain the design decisions here, but call_str_ret only handles functions that have been loaded, not external functions or intrinsics.
As a workaround, you can load a little shim function that just calls off to the appropriate function:
use dyon::{Module, Runtime, Variable};
use std::sync::Arc;
fn main() {
let mut dyon_runtime = Runtime::new();
let mut module = Module::new();
let shim = Arc::new("do_it(x) = sin(x)".into());
dyon::load_str("main.rs", shim, &mut module).expect("Unable to load shim function");
let dyon_module = Arc::new(module);
let v = dyon_runtime.call_str_ret("do_it", &[Variable::f64(90.0)], &dyon_module);
match v {
Err(e) => {
eprintln!("Error: {:?}", e);
}
Ok(v) => {
println!("Called sin - result {:?}", v);
}
};
}
Called sin - result F64(0.8939966636005579, None)
call_str() only cares about one type of function call. I don't know why they do this, but one solution would be to do it yourself:
use dyon::{ast, Module, Runtime, Variable};
use range::Range;
use std::cell::Cell;
use std::sync::Arc;
fn main() {
let mut dyon_runtime = Runtime::new();
let module = Module::new();
let name: Arc<String> = Arc::new("sin".into());
let f_index = Cell::new(module.find_function(&name, 0));
let args = vec![ast::Expression::Variable(Box::new((
Range::empty(0),
Variable::F64(1.0, None),
)))];
let call = ast::Call {
alias: None,
name,
f_index,
args,
custom_source: None,
source_range: Range::empty(0),
};
let dyon_module = Arc::new(module);
println!("{:?}", dyon_runtime.call(&call, &dyon_module));
}
Both of the other answers led me to a solution that works cleanly for both cases:
I took the Runtime.call_str_ret and modified it to use any non-None result from module.find_function. IMO the code is actually cleaner than the original version in Runtime. I've submitted a PR for this which has been merged, so releases of Dyon after 0.40.0 will have call_str_ret working for built-in functions.
If you can't use a more recent version of Dyon, then you could manually apply the patch from here: https://github.com/PistonDevelopers/dyon/pull/582.
Or alternatively you could use your own version of call_str_ret, like this:
use dyon::{Module, Runtime, Variable};
use std::sync::Arc;
extern crate range;
/// Call function by name, returning a value.
pub fn call_str_ret_ex(
runtime:&mut Runtime,
function: &str,
args: &[Variable],
module: &Arc<Module>
) -> Result<Variable, String> {
use std::cell::Cell;
use range::Range;
use dyon::FnIndex;
use dyon::runtime::Flow;
use dyon::ast;
let name: Arc<String> = Arc::new(function.into());
let fn_index = module.find_function(&name, 0);
if let FnIndex::None = fn_index {
return Err(format!("Could not find function `{}`",function))
}
let call = ast::Call {
alias: None,
name: name.clone(),
f_index: Cell::new(fn_index),
args: args.iter()
.map(|arg| ast::Expression::Variable(Box::new((
Range::empty(0), arg.clone()))))
.collect(),
custom_source: None,
source_range: Range::empty(0),
};
match runtime.call(&call, &module) {
Ok((Some(val), Flow::Continue)) => Ok(val),
Err(err) => Err(err),
_ => Err("Error during call".to_owned())
}
}
This will let you write the original code as
def test_dyon_fn(
dyon_runtime: &mut Runtime
module: &Module,
fn: &str,
)
let v = call_str_ret_ex(&mut dyon_runtime, fn, &[Variable::f64(0.0)], &dyon_module);
match v {
Err(e) => {
eprintln!("Error: {:?}", e);
}
Ok(v) => {
println!("Called {:?} - result {:?}", fn, v);
}
};
fn main() {
let mut dyon_runtime = Runtime::new();
let mut module = Module::new();
let shim = Arc::new("sin_shim(x) = sin(x)".into());
dyon::load_str("main.rs", shim, &mut module).expect("Unable to load shim function");
let dyon_module = Arc::new(module);
test_dyon_fn(&mut dyon_runtime, &dyon_module, "sin");
test_dyon_fn(&mut dyon_runtime, &dyon_module, "sin_shim");
test_dyon_fn(&mut dyon_runtime, &dyon_module, "no_such");
}
This prints:
Called sin - result F64(0.0, None)
Called sin_shim - result F64(0.0, None)
Error: "Could not find function `no_such`"
Related
I am very new to Rust and decided my first program to be a brainfuck interpreter.
I plan on using jump tables as the solution for the loops.
However I decided to rewrite the method to make it look better (for my tastes) and i got an error that I can't quite understand why
Code before causes no errors:
fn process_jumps(jump_map: &mut Vec<usize>, instructions: &Vec<Inst>){
let mut stack: Vec<usize> = Vec::new();
for (i, inst) in instructions.iter().enumerate() {
match inst {
Inst::LoopOpen => stack.push(i),
Inst::LoopClose => {
jump_map[i] = stack.pop();
jump_map[jump_map[i]] = i;
}
_ => ()
}
}
}
Code after has an error (marked in code):
fn process_jumps(instructions: &Vec<Inst>) -> Vec<usize> {
let mut jump_table: Vec<usize> = Vec::new();
let mut stack: Vec<usize> = Vec::new();
for (i, inst) in instructions.iter().enumerate() {
match inst {
Inst::LoopOpen => stack.push(i),
Inst::LoopClose => {
jump_table[i] = stack.pop(); // expected `usize`, found `Option<usize>`
jump_table[jump_map[i]] = i;
}
_ => ()
}
}
return jump_table;
}
My main question is why my code before didn't need me to check the optional?
Vec's pop() method returns Option<T>, not T.
You need to get the usize value from inside that Option, just make sure you've handled the None case correctly. When you are sure None is not possible, the simplest thing you could do is to unwrap() it.
Neither of your examples should really compile, as they both try to assign Option<usize> to a Vec<usize>.
in order to learn Rust, I try to create small snippets to apply what we learn in the Rust book and implement good practices.
Have a small function to list content of a repository :
use std::{io, fs, path::PathBuf, path::Path};
pub fn get_directory_content(path: &str) -> Result<Vec<PathBuf>, io::Error> {
let _path: bool = Path::new(path).is_dir();
match _path {
true => {
let mut result = vec![];
for file in fs::read_dir(path).unwrap() {
result.push(file.unwrap().path());
}
Ok(result)
},
false => Err(io::Error::new(io::ErrorKind::Other, " is not a directory")),
}
}
my goal is to be able to catch the error if the folder does not exist without triggering a panic.
in main.rs :
mod utils;
fn main() {
let directory = "./qsdsqd";
let test = utils::get_directory_content(directory).unwrap();
println!("{:?}", a);
}
if directory exist : ok, unwrap is happy. But does anyone know a "trick" for get the content of the error in var test ? Also, can we put the name of a variable in io::ErrorKind::Other to get more precision (here : &path) ?
Next try
fn main() {
let directory = "./qsdqsd";
let a = match utils::get_directory_content(directory){
Err(e) => println!("an error: {:?}", e),
Ok(c) => println!("{:?}", c),
};
println!("{:?}", a);
}
When error, ok, we have message, but here, if we put a correct folder : a "just" print result but content is empty, and we can't say Ok(c) => c for just return Ok content from function :/
Have a small function to list content of a repository :
That's already a pretty bad start, because it combines a TOCTOU with unnecessary extra work: if you're checking is_dir then trying to read the directory, it's possible for the entry to get deleted or swapped from under you.
This is a shame, since read_dir already does exactly what you want:
pub fn get_directory_content(path: &str) -> Result<Vec<PathBuf>, io::Error> {
let mut result = vec![];
for file in fs::read_dir(path)? {
result.push(file.unwrap().path());
}
Ok(result)
}
And you can apply this to the individual entries as well:
pub fn get_directory_content(path: &str) -> Result<Vec<PathBuf>, io::Error> {
let mut result = vec![];
for file in fs::read_dir(path)? {
result.push(file?.path());
}
Ok(result)
}
When error, ok, we have message, but here, if we put a correct folder : a "just" print result but content is empty, and we can't say Ok(c) => c for just return Ok content from function :/
Sure you can, however you still have to do something for the Err case: as most things in Rust, match is an expression, so all the branches need to return values of the same type... or not return at all:
let a = match get_directory_content(directory) {
Err(e) => {
println!("an error: {:?}", e);
return;
}
Ok(c) => c,
};
return has type !, which is Rust's "bottom" type: it's compatible with everything, because return does not "terminate", and thus there's npo reason for it to be incompatible with anything.
Alternatively, you could update main to return a Result as well, though that also requires updating it to return a value:
fn main() -> Result<(), io::Error> {
let directory = "./.config";
let a = get_directory_content(directory)?;
println!("{:?}", a);
Ok(())
}
You need to return c from your match statement.
Further, you need to do something in the Err case other than just print. What should a be in the error case?
I assume that you simply want to end the program, so I inserted a return.
mod utils {
use std::{fs, io, path::Path, path::PathBuf};
pub fn get_directory_content(path: &str) -> Result<Vec<PathBuf>, io::Error> {
let _path: bool = Path::new(path).is_dir();
match _path {
true => {
let mut result = vec![];
for file in fs::read_dir(path).unwrap() {
result.push(file.unwrap().path());
}
Ok(result)
}
false => Err(io::Error::new(io::ErrorKind::Other, " is not a directory")),
}
}
}
fn main() {
let directory = "./qsdqsd";
let a = match utils::get_directory_content(directory) {
Err(e) => {
println!("an error: {:?}", e);
return;
}
Ok(c) => {
println!("{:?}", c);
c
}
};
println!("{:?}", a);
}
["./qsdqsd/a.txt"]
["./qsdqsd/a.txt"]
DISCLAIMER: My answer is very much superficial. #Masklinn goes into much more detail about the "cleanest way" and other issues with the given code.
Because this is the accepted answer (at the time of writing), here is how a "cleanest way" version of the code could look like:
use std::{fs, io, path::PathBuf};
pub fn get_directory_content(path: &str) -> Result<Vec<PathBuf>, io::Error> {
let mut result = vec![];
for file in fs::read_dir(path)? {
result.push(file?.path());
}
Ok(result)
}
fn main() {
let directory = "./qsdqsd2";
let a = match get_directory_content(directory) {
Err(e) => {
println!("an error: {:?}", e);
return;
}
Ok(c) => c,
};
println!("{:?}", a);
}
["./qsdqsd/a.txt"]
Alternatively, you could have main() return a Result, which makes this even cleaner:
use std::{fs, io, path::PathBuf};
pub fn get_directory_content(path: &str) -> Result<Vec<PathBuf>, io::Error> {
let mut result = vec![];
for file in fs::read_dir(path)? {
result.push(file?.path());
}
Ok(result)
}
fn main() -> Result<(), io::Error> {
let directory = "./qsdqsd";
let a = get_directory_content(directory)?;
println!("{:?}", a);
Ok(())
}
I do check function results on assignment using match statement. In some cases I want to exit the program with an error message like panic!() does. But how can I create a function or macro that can be used everywhere?
Example:
let args = match args::Args::parse() {
Ok(args) => args,
Err(e) => someerror("bla")
};
let mut statedoc = match state_loader.load() {
Ok(states) => states,
Err(e) => someerror("blub")
};
What does someerror() need to return to work everywhere?
One way is to use diverging function. Use the following syntax:
fn someerror(msg: &str) -> ! { // Note the `-> !` here
eprintln!("Error: {}", msg);
panic!();
}
fn main() {
let r: Result<i32, &str> = Err("hello");
let x = match r {
Ok(x) => x,
Err(e) => someerror(e),
};
println!("x = {}", x);
}
Remember that main can return a Result and you can use the ?-operator everywhere:
fn foo() -> Result<i32, &'static str> {
Err("Nope!")
}
fn main() -> Result<(), &'static str> {
let x = 5 * foo()?;
println!("{}", x);
Ok(())
}
When executed, the above program will just print "Error: Nope!" and have an exit status not equal to zero. To support more kinds of errors, you can have a a custom enum to wrap those and appropriate implementations of Into, so you can just do let args = args::Args::parse()?;. Any errors will bubble up to main() and cause the error to be printed out.
I am writing a server using rustls and hyper and wish to peek and then parse the TcpStream to then accept the corresponding tokio_rustls::TlsAcceptor I want. However, this leads me to use both async and non async functions (tokio::net::TcpStream::peek and tokio_rustls::TlsAcceptor::accept) on the stream, which as been causing me trouble. Simply adding an async block for the peek function gives me an "unused implementer of `core::future::future::Future` that must be used" error and changing move to async move does not work.
I'm wondering if there is some way to get around this, perhaps by not using and_then()?
// Dependencies: futures-util = "0.3.1", rustls = "0.18"
// tokio = {version = "0.2", features = ["full"]}, tokio-rustls = "0.14.0"
use tokio::net::{TcpListener, TcpStream};
use tokio_rustls::server::TlsStream;
use tokio_rustls::TlsAcceptor;
use std::{sync, io};
use futures_util::{
future::TryFutureExt,
stream::{StreamExt, TryStreamExt},
};
#[tokio::main]
async fn run_server() -> Result<(), Box<dyn std::error::Error + Send + Sync>>{
let addr = format!("127.0.0.1:{}", 8000);
let mut tcp = TcpListener::bind(&addr).await?;
let tls_config = sync::Arc::new(rustls::ServerConfig::new(rustls::NoClientAuth::new()));
let tls_acceptor = TlsAcceptor::from(tls_config);
let mut v = vec![0u8; 16 * 1024];
// main focus of question
let incoming_tls_stream = tcp
.incoming()
.map_err(|e| error(format!("Incoming failed: {:?}", e)))
.and_then(move |mut s: TcpStream| {
let n: usize = s.peek(&mut v).await.unwrap();
println!("{:}", n);
// parse something from stream
let parsed = do_something(&v[..n]);
println!("{:}", parsed);
tls_acceptor.accept(s).map_err(|e| {
println!("Client-connection error...");
error(format!("TLS Error: {:?}", e))
})
})
.boxed();
// ...
return Ok(());
}
fn main() {
if let Err(e) = run_server() {
eprintln!("FAILED: {}", e);
std::process::exit(1);
}
}
fn error(err: String) -> io::Error {
io::Error::new(io::ErrorKind::Other, err)
}
fn do_something(bytes: &[u8]) -> &str {
return "test";
}
I'm trying to make a Stream that would wait until a specific character is in buffer. I know there's read_until() on BufRead but I actually need a custom solution, as this is a stepping stone to implement waiting until a specific string in in buffer (or, for example, a regexp match happens).
In my project where I first encountered the problem, problem was that future processing just hanged when I get a Ready(_) from inner future and return NotReady from my function. I discovered I shouldn't do that per docs (last paragraph). However, what I didn't get, is what's the actual alternative that is promised in that paragraph. I read all the published documentation on the Tokio site and it doesn't make sense for me at the moment.
So following is my current code. Unfortunately I couldn't make it simpler and smaller as it's already broken. Current result is this:
Err(Custom { kind: Other, error: Error(Shutdown) })
Err(Custom { kind: Other, error: Error(Shutdown) })
Err(Custom { kind: Other, error: Error(Shutdown) })
<ad infinum>
Expected result is getting some Ok(Ready(_)) out of it, while printing W and W', and waiting for specific character in buffer.
extern crate futures;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_io_timeout;
extern crate tokio_process;
use futures::stream::poll_fn;
use futures::{Async, Poll, Stream};
use tokio_core::reactor::Core;
use tokio_io::AsyncRead;
use tokio_io_timeout::TimeoutReader;
use tokio_process::CommandExt;
use std::process::{Command, Stdio};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
struct Process {
child: tokio_process::Child,
stdout: Arc<Mutex<tokio_io_timeout::TimeoutReader<tokio_process::ChildStdout>>>,
}
impl Process {
fn new(
command: &str,
reader_timeout: Option<Duration>,
core: &tokio_core::reactor::Core,
) -> Self {
let mut cmd = Command::new(command);
let cat = cmd.stdout(Stdio::piped());
let mut child = cat.spawn_async(&core.handle()).unwrap();
let stdout = child.stdout().take().unwrap();
let mut timeout_reader = TimeoutReader::new(stdout);
timeout_reader.set_timeout(reader_timeout);
let timeout_reader = Arc::new(Mutex::new(timeout_reader));
Self {
child,
stdout: timeout_reader,
}
}
}
fn work() -> Result<(), ()> {
let window = Arc::new(Mutex::new(Vec::new()));
let mut core = Core::new().unwrap();
let process = Process::new("cat", Some(Duration::from_secs(20)), &core);
let mark = Arc::new(Mutex::new(b'c'));
let read_until_stream = poll_fn({
let window = window.clone();
let timeout_reader = process.stdout.clone();
move || -> Poll<Option<u8>, std::io::Error> {
let mut buf = [0; 8];
let poll;
{
let mut timeout_reader = timeout_reader.lock().unwrap();
poll = timeout_reader.poll_read(&mut buf);
}
match poll {
Ok(Async::Ready(0)) => Ok(Async::Ready(None)),
Ok(Async::Ready(x)) => {
{
let mut window = window.lock().unwrap();
println!("W: {:?}", *window);
println!("buf: {:?}", &buf[0..x]);
window.extend(buf[0..x].into_iter().map(|x| *x));
println!("W': {:?}", *window);
if let Some(_) = window.iter().find(|c| **c == *mark.lock().unwrap()) {
Ok(Async::Ready(Some(1)))
} else {
Ok(Async::NotReady)
}
}
}
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(e) => Err(e),
}
}
});
let _stream_thread = thread::spawn(move || {
for o in read_until_stream.wait() {
println!("{:?}", o);
}
});
match core.run(process.child) {
Ok(_) => {}
Err(e) => {
println!("Child error: {:?}", e);
}
}
Ok(())
}
fn main() {
work().unwrap();
}
This is complete example project.
If you need more data you need to call poll_read again until you either find what you were looking for or poll_read returns NotReady.
You might want to avoid looping in one task for too long, so you can build yourself a yield_task function to call instead if poll_read didn't return NotReady; it makes sure your task gets called again ASAP after other pending tasks were run.
To use it just run return yield_task();.
fn yield_inner() {
use futures::task;
task::current().notify();
}
#[inline(always)]
pub fn yield_task<T, E>() -> Poll<T, E> {
yield_inner();
Ok(Async::NotReady)
}
Also see futures-rs#354: Handle long-running, always-ready futures fairly #354.
With the new async/await API futures::task::current is gone; instead you'll need a std::task::Context reference, which is provided as parameter to the new std::future::Future::poll trait method.
If you're already manually implementing the std::future::Future trait you can simply insert:
context.waker().wake_by_ref();
return std::task::Poll::Pending;
Or build yourself a Future-implementing type that yields exactly once:
pub struct Yield {
ready: bool,
}
impl core::future::Future for Yield {
type Output = ();
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> {
let this = self.get_mut();
if this.ready {
core::task::Poll::Ready(())
} else {
cx.waker().wake_by_ref();
this.ready = true; // ready next round
core::task::Poll::Pending
}
}
}
pub fn yield_task() -> Yield {
Yield { ready: false }
}
And then use it in async code like this:
yield_task().await;