I am trying to write a NES emulator.
I have created a lookup table that contains all the instructions for the 6502. Each Instruction contains the name of the instruction, a pointer to the method that is the instruction, a pointer to the address mode method, and how many cycles the instruction takes.
These are the structures for the CPU (Nes6502) and a structure for what each Instruction contains.
pub struct Nes6502 {
bus: Bus,
/// Accumulator Register
a: u8,
/// X Register
x: u8,
/// Y Register
y: u8,
/// Stack pointer (pointers to a location on the bus)
stkp: u8,
/// Program counter
pc: u16,
/// Status Register
status: u8,
fetched: u8,
addr_abs: u16,
addr_rel: u16,
opcode: u8,
cycles: u8,
lookup: Vec<Instruction>,
}
struct Instruction {
name: String,
operate: fn() -> u8,
addrmode: fn() -> u8,
cycles: u8,
}
But the issue I run into is when I try to initialize the lookup table for the instructions
impl Nes6502 {
fn new() -> Nes6502 {
let mut ram= [0; MEM_SIZE];
ram.iter_mut().for_each(|r| *r = 0x00);
let mut nes = Nes6502 {
a: 0x00,
x: 0x00,
y: 0x00,
stkp: 0x00,
pc: 0x0000,
status: 0x00,
fetched: 0x00,
addr_abs: 0x0000,
addr_rel: 0x00,
opcode: 0x00,
cycles: 0,
lookup: Vec::new(),
bus: Bus {
ram
}
};
nes.lookup = vec![
Instruction{ name: String::from("BRK"), operate: || nes.BRK(), addrmode: || nes.IMM(), cycles: 7 } // ...
]
nes
}
// ...
}
In the part where I initialize the lookup table with all the instructions I get this error
error[E0308]: mismatched types
--> src/nes_6502.rs:86:63
|
86 | ... Instruction{ name: String::from("BRK"), operate: || nes.BRK(), addrmode: || nes.IMM(), cycles: 7 }// ,Instruction{ name: String::fr...
| ^^^^^^^^^^^^ expected fn pointer, found closure
|
= note: expected fn pointer `fn() -> u8`
found closure `[closure#src/nes_6502.rs:86:63: 86:75]`
note: closures can only be coerced to `fn` types if they do not capture any variables
--> src/nes_6502.rs:86:66
|
86 | ... Instruction{ name: String::from("BRK"), operate: || nes.BRK(), addrmode: || nes.IMM(), cycles: 7 }// ,Instruction{ name: String::fr...
| ^^^ `nes` captured here
I also tried initializing it like this
nes.lookup = vec![
Instruction{ name: String::from("BRK"), operate: nes.BRK, addrmode: nes.IMM, cycles: 7 }
]
But that gave me this error
error[E0615]: attempted to take value of method `BRK` on type `Nes6502`
--> src/nes_6502.rs:86:67
|
86 | ... Instruction{ name: String::from("BRK"), operate: nes.BRK, addrmode: nes.IMM, cycles: 7 }// ,Instruction{ name: String::from("ORA"),...
| ^^^ method, not a field
|
help: use parentheses to call the method
|
86 | Instruction{ name: String::from("BRK"), operate: nes.BRK(), addrmode: nes.IMM, cycles: 7 }
I assume this is your 'minimal' example, as your code doesn't reproduce your issue directly:
struct Bus {
ram: [i32; 1024],
}
pub struct Nes6502 {
bus: Bus,
/// Accumulator Register
a: u8,
/// X Register
x: u8,
/// Y Register
y: u8,
/// Stack pointer (pointers to a location on the bus)
stkp: u8,
/// Program counter
pc: u16,
/// Status Register
status: u8,
fetched: u8,
addr_abs: u16,
addr_rel: u16,
opcode: u8,
cycles: u8,
lookup: Vec<Instruction>,
}
struct Instruction {
name: String,
operate: fn() -> u8,
addrmode: fn() -> u8,
cycles: u8,
}
const MEM_SIZE: usize = 1024;
impl Nes6502 {
fn new() -> Nes6502 {
let mut ram = [0; MEM_SIZE];
ram.iter_mut().for_each(|r| *r = 0x00);
let mut nes = Nes6502 {
a: 0x00,
x: 0x00,
y: 0x00,
stkp: 0x00,
pc: 0x0000,
status: 0x00,
fetched: 0x00,
addr_abs: 0x0000,
addr_rel: 0x00,
opcode: 0x00,
cycles: 0,
lookup: Vec::new(),
bus: Bus { ram },
};
nes.lookup = vec![
Instruction {
name: String::from("BRK"),
operate: || nes.BRK(),
addrmode: || nes.IMM(),
cycles: 7,
}, // ...
];
nes
}
fn BRK(&self) -> u8 {
todo!()
}
fn IMM(&self) -> u8 {
todo!()
}
// ...
}
error[E0308]: mismatched types
--> src/lib.rs:62:26
|
62 | operate: || nes.BRK(),
| ^^^^^^^^^^^^ expected fn pointer, found closure
|
= note: expected fn pointer `fn() -> u8`
found closure `[closure#src/lib.rs:62:26: 62:38]`
note: closures can only be coerced to `fn` types if they do not capture any variables
--> src/lib.rs:62:29
|
62 | operate: || nes.BRK(),
| ^^^ `nes` captured here
error[E0308]: mismatched types
--> src/lib.rs:63:27
|
63 | addrmode: || nes.IMM(),
| ^^^^^^^^^^^^ expected fn pointer, found closure
|
= note: expected fn pointer `fn() -> u8`
found closure `[closure#src/lib.rs:63:27: 63:39]`
note: closures can only be coerced to `fn` types if they do not capture any variables
--> src/lib.rs:63:30
|
63 | addrmode: || nes.IMM(),
| ^^^ `nes` captured here
fn vs Fn/FnMut/FnOnce
fn is a function pointer. It is simply an address that points to some executable function. No data can be attached to an fn.
FnOnce is a trait that describes some object that can be executed at least once. The object gets consumed in the process of executing it.
FnMut is a trait that describes some object that can be executed multiple times, but either has a side effect or changes its internal state in the process. Mutable access to the object is required to execute it. Every FnMut is also FnOnce.
Fn is a trait that describes some object that can be executed many times without side effects or internal state changes. A simple immutable reference is required to execute it. Every Fn is also FnMut and FnOnce.
Fn, FnMut and FnOnce are all based on actual objects in memory, and not just pointers. Therefore those can carry data.
Why is this important for your case?
|| nes.BRK() is a closure that takes no argument, but uses the nes object. Therefore it needs to store the reference to the nes object somewhere.
So the first intuition would be to change fn to Box<dyn Fn>, like this:
struct Bus {
ram: [i32; 1024],
}
pub struct Nes6502 {
bus: Bus,
/// Accumulator Register
a: u8,
/// X Register
x: u8,
/// Y Register
y: u8,
/// Stack pointer (pointers to a location on the bus)
stkp: u8,
/// Program counter
pc: u16,
/// Status Register
status: u8,
fetched: u8,
addr_abs: u16,
addr_rel: u16,
opcode: u8,
cycles: u8,
lookup: Vec<Instruction>,
}
struct Instruction {
name: String,
operate: Box<dyn Fn() -> u8>,
addrmode: Box<dyn Fn() -> u8>,
cycles: u8,
}
const MEM_SIZE: usize = 1024;
impl Nes6502 {
fn new() -> Nes6502 {
let mut ram = [0; MEM_SIZE];
ram.iter_mut().for_each(|r| *r = 0x00);
let mut nes = Nes6502 {
a: 0x00,
x: 0x00,
y: 0x00,
stkp: 0x00,
pc: 0x0000,
status: 0x00,
fetched: 0x00,
addr_abs: 0x0000,
addr_rel: 0x00,
opcode: 0x00,
cycles: 0,
lookup: Vec::new(),
bus: Bus { ram },
};
nes.lookup = vec![
Instruction {
name: String::from("BRK"),
operate: Box::new(|| nes.BRK()),
addrmode: Box::new(|| nes.IMM()),
cycles: 7,
}, // ...
];
nes
}
fn BRK(&self) -> u8 {
todo!()
}
fn IMM(&self) -> u8 {
todo!()
}
// ...
}
error[E0506]: cannot assign to `nes.lookup` because it is borrowed
--> src/lib.rs:59:9
|
59 | nes.lookup = vec![
| ^^^^^^^^^^ assignment to borrowed `nes.lookup` occurs here
...
62 | operate: Box::new(|| nes.BRK()),
| ----------------------
| | | |
| | | borrow occurs due to use in closure
| | borrow of `nes.lookup` occurs here
| cast requires that `nes` is borrowed for `'static`
error[E0597]: `nes` does not live long enough
--> src/lib.rs:62:38
|
62 | operate: Box::new(|| nes.BRK()),
| ------------^^^-------
| | | |
| | | borrowed value does not live long enough
| | value captured here
| cast requires that `nes` is borrowed for `'static`
...
69 | }
| - `nes` dropped here while still borrowed
error[E0597]: `nes` does not live long enough
--> src/lib.rs:63:39
|
63 | addrmode: Box::new(|| nes.IMM()),
| ------------^^^-------
| | | |
| | | borrowed value does not live long enough
| | value captured here
| cast requires that `nes` is borrowed for `'static`
...
69 | }
| - `nes` dropped here while still borrowed
error[E0505]: cannot move out of `nes` because it is borrowed
--> src/lib.rs:68:9
|
62 | operate: Box::new(|| nes.BRK()),
| ----------------------
| | | |
| | | borrow occurs due to use in closure
| | borrow of `nes` occurs here
| cast requires that `nes` is borrowed for `'static`
...
68 | nes
| ^^^ move out of `nes` occurs here
This brings us to the next problem though: The closure outlives the current function, and therefore the compiler cannot guarantee that the nes object lives longer than the closure. Further, for as long as the closure borrows the nes object, no mutable reference to the nes can exist, which is probably not what you want. I'm sure you want to modify the nes object.
So what you really want is to only borrow the nes object while executing the closure. This can be achieved by passing the nes object into the closure as a function argument.
Once we have done that, the closure now no longer stores any references or objects, and we can use a plain fn function pointer again:
struct Bus {
ram: [i32; 1024],
}
pub struct Nes6502 {
bus: Bus,
/// Accumulator Register
a: u8,
/// X Register
x: u8,
/// Y Register
y: u8,
/// Stack pointer (pointers to a location on the bus)
stkp: u8,
/// Program counter
pc: u16,
/// Status Register
status: u8,
fetched: u8,
addr_abs: u16,
addr_rel: u16,
opcode: u8,
cycles: u8,
lookup: Vec<Instruction>,
}
struct Instruction {
name: String,
operate: fn(&mut Nes6502) -> u8,
addrmode: fn(&Nes6502) -> u8,
cycles: u8,
}
const MEM_SIZE: usize = 1024;
impl Nes6502 {
fn new() -> Nes6502 {
let mut ram = [0; MEM_SIZE];
ram.iter_mut().for_each(|r| *r = 0x00);
let mut nes = Nes6502 {
a: 0x00,
x: 0x00,
y: 0x00,
stkp: 0x00,
pc: 0x0000,
status: 0x00,
fetched: 0x00,
addr_abs: 0x0000,
addr_rel: 0x00,
opcode: 0x00,
cycles: 0,
lookup: Vec::new(),
bus: Bus { ram },
};
nes.lookup = vec![
Instruction {
name: String::from("BRK"),
operate: |nes| nes.BRK(),
addrmode: |nes| nes.IMM(),
cycles: 7,
}, // ...
];
nes
}
fn BRK(&self) -> u8 {
todo!()
}
fn IMM(&self) -> u8 {
todo!()
}
// ...
}
Another minor nitpick
The name of your Instruction is most likely already known at compile time, so it saves time and resources to use &'static str instead:
struct Instruction {
name: &'static str,
operate: fn(&mut Nes6502) -> u8,
addrmode: fn(&Nes6502) -> u8,
cycles: u8,
}
// ...
nes.lookup = vec![
Instruction {
name: "BRK",
operate: |nes| nes.BRK(),
addrmode: |nes| nes.IMM(),
cycles: 7,
}, // ...
];
// ...
Related
I am new to Rust and I am writing a recursive directory traversal program. This project is just an opportunity to learn Rust and parallelism with Rayon. This question is a continuation of this question which #KevinReid helped out a lot with.
Below is my attempt to use partition_map() followed by the errors I am receiving.
use std::fs;
use std::path::PathBuf;
use rayon::iter::{Either, IntoParallelIterator, ParallelIterator};
#[derive(Debug)]
struct Node {
path: PathBuf,
files: Vec<PathBuf>,
folders: Vec<Box<Node>>,
}
impl Node {
pub fn new(path: PathBuf) -> Self {
Node {
path: path,
files: Vec::new(),
folders: Vec::new(),
}
}
pub fn burrow(&mut self) {
let mut contents: Vec<PathBuf> = ls_dir(&self.path);
let ret: (Vec<PathBuf>, Vec<Box<Node>>) = contents.into_par_iter().partition_map(|item|
if item.is_file() {
self.files.push(item);
Either::Left(self.files)
} else {
let mut new_folder = Node::new(item);
new_folder.burrow();
self.folders.push(Box::new(new_folder));
Either::Right(self.folders)
});
println!("{:?}", ret);
}
}
fn ls_dir(path: &PathBuf) -> Vec<PathBuf> {
let mut contents: Vec<PathBuf> = Vec::new();
let current_dir: fs::ReadDir = fs::read_dir(path).unwrap();
for file in current_dir {
contents.push(file.unwrap().path());
}
contents
}
fn main() {
let root_path: &str = ".";
let root: PathBuf = PathBuf::from(root_path);
let contents: Vec<PathBuf> = ls_dir(&root);
let mut node: Node = Node::new(root);
node.burrow();
}
error[E0277]: the trait bound `Vec<PathBuf>: ParallelExtend<Vec<PathBuf>>` is not satisfied
--> src/main.rs:31:76
|
31 | let ret: (Vec<PathBuf>, Vec<Box<Node>>) = contents.into_par_iter().partition_map(|item|
| ^^^^^^^^^^^^^ the trait `ParallelExtend<Vec<PathBuf>>` is not implemented for `Vec<PathBuf>`
|
= help: the following implementations were found:
<Vec<T> as ParallelExtend<&'a T>>
<Vec<T> as ParallelExtend<T>>
note: required by a bound in `partition_map`
--> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.3/src/iter/mod.rs:2167:29
|
2167 | A: Default + Send + ParallelExtend<L>,
| ^^^^^^^^^^^^^^^^^ required by this bound in `partition_map`
error[E0277]: the trait bound `Vec<Box<Node>>: ParallelExtend<Vec<Box<Node>>>` is not satisfied
--> src/main.rs:31:76
|
31 | let ret: (Vec<PathBuf>, Vec<Box<Node>>) = contents.into_par_iter().partition_map(|item|
| ^^^^^^^^^^^^^ the trait `ParallelExtend<Vec<Box<Node>>>` is not implemented for `Vec<Box<Node>>`
|
= help: the following implementations were found:
<Vec<T> as ParallelExtend<&'a T>>
<Vec<T> as ParallelExtend<T>>
note: required by a bound in `partition_map`
--> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.3/src/iter/mod.rs:2168:29
|
2168 | B: Default + Send + ParallelExtend<R>,
| ^^^^^^^^^^^^^^^^^ required by this bound in `partition_map`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `my-project` due to 2 previous errors
exit status 101
It appears that ParallelExtend<T> for Vec<T> is producing the error because of what T is, namely, PathBuf and Box<Node>. I have seen a smaller non-recursive example where T is &str, for example in which these errors are not present. So the question is if this is fixable and just not implemented correctly, or PathBuf and Box<T> inherently do not satisfy something that ParallelExtend requires.
To test if the type T was the issue I ran
pub fn burrow(&mut self) {
let mut contents: Vec<PathBuf> = ls_dir(&self.path);
let ret: (Vec<&str>, Vec<&str>) = contents.into_par_iter().partition_map(|item|
if item.is_file() {
self.files.push(item);
Either::Left("test")
} else {
let mut new_folder = Node::new(item);
new_folder.burrow();
self.folders.push(Box::new(new_folder));
Either::Right("test")
});
println!("{:?}", ret);
}
and received
error[E0596]: cannot borrow `*self.files` as mutable, as it is a captured variable in a `Fn` closure
--> src/main.rs:33:37
|
33 | ... self.files.push(item);
| ^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `*self.folders` as mutable, as it is a captured variable in a `Fn` closure
--> src/main.rs:38:37
|
38 | ... self.folders.push(Box::new(new_folder));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
For more information about this error, try `rustc --explain E0596`.
error: could not compile `my-project` due to 2 previous errors
exit status 101
which is a totally different issue/concept. Needless to say, with the added recursive component, I am lost in the sauce.
I have a simple struct and an implementation that looks like this.
#[derive(Debug)]
struct MyStruct {
data: u64,
}
impl MyStruct {
async fn something_async(&mut self) -> Result<(), Box<dyn Error>> {
self.data += 1;
Ok(())
}
}
I want to use MyStruct on the heap using a smart pointer and a mutex so that I can use it from multiple threads.
However, when I try to call the async function called something_async()...
tokio::spawn(async move {
let ptr = Arc::new(Mutex::new(MyStruct { data: 1 }));
let mut s = ptr.lock().unwrap();
s.something_async().await.unwrap();
println!("{:?}", s);
});
...I get the following error:
error: future cannot be sent between threads safely
--> src/main.rs:18:5
|
18 | tokio::spawn(async move {
| ^^^^^^^^^^^^ future created by async block is not `Send`
|
= help: within `impl Future<Output = [async output]>`, the trait `Send` is not implemented for `std::sync::MutexGuard<'_, MyStruct>`
note: future is not `Send` as this value is used across an await
--> src/main.rs:21:9
|
20 | let mut s = ptr.lock().unwrap();
| ----- has type `std::sync::MutexGuard<'_, MyStruct>` which is not `Send`
21 | s.something_async().await.unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `mut s` maybe used later
22 | println!("{:?}", s);
23 | });
| - `mut s` is later dropped here
note: required by a bound in `tokio::spawn`
--> /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.16.1/src/task/spawn.rs:127:21
|
127 | T: Future + Send + 'static,
| ^^^^ required by this bound in `tokio::spawn`
I am assuming that the compiler does not like me keeping a MutexGuard held across an await, so I tried this instead:
let fut = {
let mut s = ptr.lock().unwrap();
s.something_async()
};
fut.await.unwrap();
But of course then it complains about the Future outliving the mutable reference not living long enough:
error[E0597]: `s` does not live long enough
--> src/main.rs:22:13
|
20 | let fut = {
| --- borrow later stored here
21 | let mut s = ptr.lock().unwrap();
22 | s.something_async()
| ^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
23 | };
| - `s` dropped here while still borrowed
How do I call an async method on an object wrapped in an Arc<Mutex<T>>?
Make MyStruct copyable.
#[derive(Debug, Copy, Clone)]
struct MyStruct {
data: u64,
}
impl MyStruct {
async fn something_async(&mut self) -> Result<(), Box<dyn Error>> {
self.data += 1;
Ok(())
}
}
#[tokio::main]
async fn main() {
tokio::spawn(async move {
let ptr = Arc::new(Mutex::new(MyStruct { data: 1 }));
let mut s = *ptr.lock().unwrap();
s.something_async().await.unwrap();
println!("{:?}", s);
});
}
use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
use std::time::Duration;
// pyO3 module
use pyo3::prelude::*;
use pyo3::wrap_pyfunction;
use std::future::Future;
#[pyfunction]
pub fn start_server() {
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
let pool = ThreadPool::new(4);
for stream in listener.incoming() {
let stream = stream.unwrap();
pool.execute(|| {
let rt = tokio::runtime::Runtime::new().unwrap();
handle_connection(stream, rt, &test_helper);
});
}
}
#[pymodule]
pub fn roadrunner(_: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(start_server))?;
Ok(())
}
async fn read_file(filename: String) -> String {
let con = tokio::fs::read_to_string(filename).await;
con.unwrap()
}
async fn test_helper(contents: &mut String, filename: String) {
// this function will accept custom function and return
*contents = tokio::task::spawn(read_file(filename.clone()))
.await
.unwrap();
}
pub fn handle_connection(
mut stream: TcpStream,
runtime: tokio::runtime::Runtime,
test: &dyn Fn(&mut String, String) -> (dyn Future<Output = ()> + 'static),
) {
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap();
let get = b"GET / HTTP/1.1\r\n";
let sleep = b"GET /sleep HTTP/1.1\r\n";
let (status_line, filename) = if buffer.starts_with(get) {
("HTTP/1.1 200 OK", "hello.html")
} else if buffer.starts_with(sleep) {
thread::sleep(Duration::from_secs(5));
("HTTP/1.1 200 OK", "hello.html")
} else {
("HTTP/1.1 404 NOT FOUND", "404.html")
};
let mut contents = String::new();
let future = test_helper(&mut contents, String::from(filename));
runtime.block_on(future);
let response = format!(
"{}\r\nContent-Length: {}\r\n\r\n{}",
status_line,
contents.len(),
contents
);
stream.write(response.as_bytes()).unwrap();
stream.flush().unwrap();
}
I am trying to create a module where I need to pass an async function as an argument. I have passed the element but I am unable to deduce what should I do from the error message. It is telling me that there is some mismatch in type inference.
Here is the error message I am getting on cargo check
error[E0271]: type mismatch resolving `for<'r> <for<'_> fn(&mut String, String) -> impl Future {test_helper} as FnOnce<(&'r mut String, String)>>::Output == (dyn Future<Output = ()> + 'static)`
--> src/lib.rs:124:43
|
124 | handle_connection(stream, rt, &test_helper);
| ^^^^^^^^^^^^ expected trait object `dyn Future`, found opaque type
...
140 | async fn test_helper(contents: &mut String, filename: String) {
| - checked the `Output` of this `async fn`, found opaque type
|
= note: while checking the return type of the `async fn`
= note: expected trait object `(dyn Future<Output = ()> + 'static)`
found opaque type `impl Future`
= note: required for the cast to the object type `dyn for<'r> Fn(&'r mut String, String) -> (dyn Future<Output = ()> + 'static)`
error: aborting due to previous error
Please let me know what change should be made here. Thanks in advance.
You are writing a function type that returns a dyn type, not a reference to it, but the unsized type itself, that is not possible. Every time you want to write something like this, try using a generic instead:
pub fn handle_connection<F>(
mut stream: TcpStream,
runtime: tokio::runtime::Runtime,
test: &dyn Fn(&mut String, String) -> F,
)
where F: Future<Output = ()> + 'static
This now fails with this weird error:
error[E0308]: mismatched types
--> src/lib.rs:19:43
|
19 | handle_connection(stream, rt, &test_helper);
| ^^^^^^^^^^^^ one type is more general than the other
|
= note: expected associated type `<for<'_> fn(&mut String, String) -> impl Future {test_helper} as FnOnce<(&mut String, String)>>::Output`
found associated type `<for<'_> fn(&mut String, String) -> impl Future {test_helper} as FnOnce<(&mut String, String)>>::Output`
But this is expected too, your future is holding a reference to that &mut String you are passing, so it is not 'static anymore. The solution is just to add a lifetime generic parameter:
pub fn handle_connection<'a, F>(
mut stream: TcpStream,
runtime: tokio::runtime::Runtime,
test: &dyn Fn(&'a mut String, String) -> F,
)
where F: Future<Output = ()> + 'a
And now it should compile.
I have the following higher-order function
fn ensure_tonicty(tone_fn: &fn(&f64, &f64) -> bool) -> impl Fn(&Vec<f64>) -> bool {
return |floats: &Vec<f64>| -> bool {
let first = floats.first().unwrap();
let rest = &floats[1..];
fn f(tone_fn: &fn(&f64, &f64) -> bool, prev: &f64, xs: &[f64]) -> bool {
match xs.first() {
Some(x) => tone_fn(prev, x) && f(tone_fn, x, &xs[1..]),
None => true,
}
};
return f(tone_fn, first, rest);
};
}
My goal is to return this lambda. I can't figure out how to effectively use tone_fn here though.
The code above errors out:
error[E0621]: explicit lifetime required in the type of `tone_fn`
--> src/lib.rs:1:56
|
1 | fn ensure_tonicty(tone_fn: &fn(&f64, &f64) -> bool) -> impl Fn(&Vec<f64>) -> bool {
| ----------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required
| |
| help: add explicit lifetime `'static` to the type of `tone_fn`: `&'static for<'r, 's> fn(&'r f64, &'s f64) -> bool`
If I try to include a lifetime though, I am not sure how to type impl Fn, and include the lifetime
// where do I write `'a`?
fn ensure_tonicty<'a>(tone_fn: &'a fn(&f64, &f64) -> bool) -> impl Fn(&Vec<f64>) -> bool {
I could write this as a macro and get past this, but I'm curious if there's a way I can do this without going the macro route.
You are using a lot of references, which don't seem necessary, and make it harder to figure this all out:
A fn is already a function pointer, so you can pass them around by value instead of using another layer of references. This is easier because a function pointer is 'static.
All those &f64s are immutable, so could be replaced with f64 without changing the logic. This should be the same speed as (or possibly faster than) using a reference.
Once you do that, you won't have many reference left, and it will be clearer which are causing the problem:
fn ensure_tonicty(tone_fn: fn(f64, f64) -> bool) -> impl Fn(&Vec<f64>) -> bool {
|floats: &Vec<f64>| -> bool {
let first = *floats.first().unwrap();
let rest = &floats[1..];
fn f(tone_fn: fn(f64, f64) -> bool, prev: f64, xs: &[f64]) -> bool {
match xs.first() {
Some(&x) => tone_fn(prev, x) && f(tone_fn, x, &xs[1..]),
None => true,
}
};
f(tone_fn, first, rest);
};
}
Now, the error is:
error[E0373]: closure may outlive the current function, but it borrows `tone_fn`, which is owned by the current function
--> src/lib.rs:2:12
|
2 | return |floats: &Vec<f64>| -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ may outlive borrowed value `tone_fn`
...
11 | return f(tone_fn, first, rest);
| ------- `tone_fn` is borrowed here
|
note: closure is returned here
--> src/lib.rs:2:12
|
2 | return |floats: &Vec<f64>| -> bool {
| ____________^
3 | | let first = *floats.first().unwrap();
4 | | let rest = &floats[1..];
5 | | fn f(tone_fn: fn(f64, f64) -> bool, prev: f64, xs: &[f64]) -> bool {
... |
11 | | return f(tone_fn, first, rest);
12 | | };
| |_____^
help: to force the closure to take ownership of `tone_fn` (and any other referenced variables), use the `move` keyword
|
2 | return move |floats: &Vec<f64>| -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The help section tells you exactly how to fix it: make the closure move its environment. The result is:
fn ensure_tonicty(tone_fn: fn(f64, f64) -> bool) -> impl Fn(&[f64]) -> bool {
move |floats: &[f64]| -> bool {
let first = floats[0];
let rest = &floats[1..];
fn f(tone_fn: fn(f64, f64) -> bool, prev: f64, xs: &[f64]) -> bool {
match xs.first() {
Some(&x) => tone_fn(prev, x) && f(tone_fn, x, &xs[1..]),
None => true,
}
};
f(tone_fn, first, rest)
}
}
If you return a closure from another function, you will nearly always need this keyword. Otherwise, any variables mentioned in the closure will be references to values that will go out of scope when the function ends. Using the move keyword moves those values so they go wherever the closure goes.
Also notice the other changes I made, to make the code more idiomatic:
Use expressions instead of return keyword.
Use &[f64] instead of &Vec<f64> in function arguments (see Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?).
I'd like to take a regular iterator and turn it into a stream so that I can do further stream processing. The trouble is that I may have an iterator or an error to deal with. I think I'm pretty close with this:
#[macro_use]
extern crate log;
extern crate futures; // 0.1.21
extern crate tokio;
use futures::prelude::*;
use futures::{future, stream};
use std::fmt::Debug;
use std::net::{SocketAddr, ToSocketAddrs};
fn resolve(addrs: impl ToSocketAddrs + Debug) -> impl Stream<Item = SocketAddr, Error = ()> {
match addrs.to_socket_addrs() {
Ok(iter) => stream::unfold(iter, |iter| match iter.next() {
Some(a) => Some(future::ok((a, iter))),
None => None,
}),
Err(e) => {
error!("could not resolve socket addresses {:?}: {:?}", addrs, e);
stream::empty()
}
}
}
fn main() {
let task = resolve("1.2.3.4:12345")
.map_err(|e| error!("{:?}", e))
.for_each(|addr| info!("{:?}", addr))
.fold();
tokio::run(task);
}
playground
error[E0308]: match arms have incompatible types
--> src/main.rs:12:5
|
12 | / match addrs.to_socket_addrs() {
13 | | Ok(iter) => stream::unfold(iter, |iter| match iter.next() {
14 | | Some(a) => Some(future::ok((a, iter))),
15 | | None => None,
... |
20 | | }
21 | | }
| |_____^ expected struct `futures::stream::Unfold`, found struct `futures::stream::Empty`
|
= note: expected type `futures::stream::Unfold<<impl ToSocketAddrs + Debug as std::net::ToSocketAddrs>::Iter, [closure#src/main.rs:13:42: 16:10], futures::FutureResult<(std::net::SocketAddr, <impl ToSocketAddrs + Debug as std::net::ToSocketAddrs>::Iter), _>>`
found type `futures::stream::Empty<_, _>`
note: match arm with an incompatible type
--> src/main.rs:17:19
|
17 | Err(e) => {
| ___________________^
18 | | error!("could not resolve socket addresses {:?}: {:?}", addrs, e);
19 | | stream::empty()
20 | | }
| |_________^
error[E0277]: the trait bound `(): futures::Future` is not satisfied
--> src/main.rs:27:10
|
27 | .for_each(|addr| info!("{:?}", addr))
| ^^^^^^^^ the trait `futures::Future` is not implemented for `()`
|
= note: required because of the requirements on the impl of `futures::IntoFuture` for `()`
error[E0599]: no method named `fold` found for type `futures::stream::ForEach<futures::stream::MapErr<impl futures::Stream, [closure#src/main.rs:26:18: 26:39]>, [closure#src/main.rs:27:19: 27:45], ()>` in the current scope
--> src/main.rs:28:10
|
28 | .fold();
| ^^^^
|
= note: the method `fold` exists but the following trait bounds were not satisfied:
`&mut futures::stream::ForEach<futures::stream::MapErr<impl futures::Stream, [closure#src/main.rs:26:18: 26:39]>, [closure#src/main.rs:27:19: 27:45], ()> : futures::Stream`
`&mut futures::stream::ForEach<futures::stream::MapErr<impl futures::Stream, [closure#src/main.rs:26:18: 26:39]>, [closure#src/main.rs:27:19: 27:45], ()> : std::iter::Iterator`
The hint is pretty obvious. The two Results I'm returning from the match differ and should be the same. Now, how can I do that so that I return a stream?
Rust is a statically typed language which means that the return type of a function has to be a single type, known at compile time. You are attempting to return multiple types, decided at runtime.
The closest solution to your original is to always return the Unfold stream:
fn resolve(addrs: impl ToSocketAddrs) -> impl Stream<Item = SocketAddr, Error = ()> {
stream::unfold(addrs.to_socket_addrs(), |r| {
match r {
Ok(mut iter) => iter.next().map(|addr| future::ok((addr, Ok(iter)))),
Err(_) => None,
}
})
}
But why reinvent the wheel?
futures::stream::iter_ok
Converts an Iterator into a Stream which is always ready to yield the next value.
Subsequent versions of the futures crate implement Stream for Either, which makes this very elegant:
fn resolve(addrs: impl ToSocketAddrs) -> impl Stream<Item = SocketAddr, Error = ()> {
match addrs.to_socket_addrs() {
Ok(iter) => stream::iter_ok(iter).left_stream(),
Err(_) => stream::empty().right_stream(),
}
}
It's straightforward to backport this functionality to futures 0.1 (maybe someone should submit it as a PR for those who are stuck on 0.1...):
enum MyEither<L, R> {
Left(L),
Right(R),
}
impl<L, R> Stream for MyEither<L, R>
where
L: Stream,
R: Stream<Item = L::Item, Error = L::Error>,
{
type Item = L::Item;
type Error = L::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
match self {
MyEither::Left(l) => l.poll(),
MyEither::Right(r) => r.poll(),
}
}
}
trait EitherStreamExt {
fn left_stream<R>(self) -> MyEither<Self, R>
where
Self: Sized;
fn right_stream<L>(self) -> MyEither<L, Self>
where
Self: Sized;
}
impl<S: Stream> EitherStreamExt for S {
fn left_stream<R>(self) -> MyEither<Self, R> {
MyEither::Left(self)
}
fn right_stream<L>(self) -> MyEither<L, Self> {
MyEither::Right(self)
}
}
Even better, use the fact that Result is an iterator and Stream::flatten exists:
fn resolve(addrs: impl ToSocketAddrs) -> impl Stream<Item = SocketAddr, Error = ()> {
stream::iter_ok(addrs.to_socket_addrs())
.map(stream::iter_ok)
.flatten()
}
Or if you really want to print errors:
fn resolve(addrs: impl ToSocketAddrs) -> impl Stream<Item = SocketAddr, Error = ()> {
stream::once(addrs.to_socket_addrs())
.map(stream::iter_ok)
.map_err(|e| eprintln!("err: {}", e))
.flatten()
}
See also:
Conditionally return empty iterator from flat_map
Conditionally iterate over one of several possible iterators
What is the correct way to return an Iterator (or any other trait)?