Rust NdArray Distance Matrix - multithreading

I am trying to write a a function that calculates distance matrices using ndarray:
extern crate ndarray;
use ndarray::{s, Array2, ArrayView1, indices_of, azip, array};
use ndarray::parallel::par_azip;
use std::f64;
type M = Array2<f64>;
fn main() {
// make some arbitrary data
let points = array!([0.,23.], [12., 13.], [15., 2.], [16., 145.], [42., 11.], [12., 12.], [11., 12.], [56., 18.], [34., 12.]);
// calculate matrix
let dist_arr = dist_to_mat(&points, &l2);
println!("{}", dist_arr.mapv(|x| (100. * x).round() / 100.))
}
// as an example, use l2 distance
fn l2(x: &ArrayView1<f64>, y: &ArrayView1<f64>) -> f64 {
let diff = x - y;
let result = (&diff * &diff).sum();
return result.sqrt()
}
pub fn dist_to_mat(
points: &Array2<f64>,
dist_fn: &dyn Fn(&ArrayView1<f64>, &ArrayView1<f64>) -> f64,
) -> M {
// initialize array
let mut distances = Array2::zeros((points.nrows(), points.nrows()));
let idx = indices_of(&distances);
// helper function to get the entries of points
let func = |i: usize, j: usize| -> f64 {
dist_fn(&points.slice(s![i, ..]), &points.slice(s![j, ..]))
};
// apply function to matrix with index array in lock-step
par_azip!((c in &mut distances, (i,j) in idx){*c = func(i,j)}); // <- error here; works if par_azip is replaced with azip.
return distances
}
While this works fine with the single-threaded azip, with par_azip I get the error:
`dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64` cannot be shared between threads safely
`dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64` cannot be shared between threads safely
help: within `[closure#<::ndarray::zip::zipmacro::azip macros>:23:6: 23:7 func:&[closure#src/main.rs:27:16: 29:6 dist_fn:&&dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64, points:&&ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 2]>>]]`, the trait `std::marker::Sync` is not implemented for `dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64`
note: required because it appears within the type `&dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64`
note: required because it appears within the type `&&dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64`
note: required because it appears within the type `[closure#src/main.rs:27:16: 29:6 dist_fn:&&dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64, points:&&ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 2]>>]`
note: required because it appears within the type `&[closure#src/main.rs:27:16: 29:6 dist_fn:&&dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64, points:&&ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 2]>>]`
note: required because it appears within the type `[closure#<::ndarray::zip::zipmacro::azip macros>:23:6: 23:7 func:&[closure#src/main.rs:27:16: 29:6 dist_fn:&&dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64, points:&&ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 2]>>]]`rustc(E0277)
<::ndarray::parallel::zipmacro::par_azip macros>(1, 50): `dyn for<'r, 's, 't0, 't1> std::ops::Fn(&'r ndarray::ArrayBase<ndarray::ViewRepr<&'s f64>, ndarray::Dim<[usize; 1]>>, &'t0 ndarray::ArrayBase<ndarray::ViewRepr<&'t1 f64>, ndarray::Dim<[usize; 1]>>) -> f64` cannot be shared between threads safely
Which object cannot be shared between threads safely: the return value of dist_fun or dist_fun? How do I fix this?

Fixed it. see <-
extern crate ndarray;
use ndarray::{s, Array2, ArrayView1, indices_of, azip, array};
use ndarray::parallel::par_azip;
use std::f64;
type M = Array2<f64>;
fn main() {
// make some arbitrary data
let points = array!([0.,23.], [12., 13.], [15., 2.], [16., 145.], [42., 11.], [12., 12.], [11., 12.], [56., 18.], [34., 12.]);
// calculate matrix
let dist_arr = dist_to_mat(&points, &l2);
println!("{}", dist_arr.mapv(|x| (100. * x).round() / 100.))
}
// as an example, use l2 distance
fn l2(x: &ArrayView1<f64>, y: &ArrayView1<f64>) -> f64 {
let diff = x - y;
let result = (&diff * &diff).sum();
return result.sqrt()
}
pub fn dist_to_mat(
points: &Array2<f64>,
dist_fn: &fn(&ArrayView1<f64>, &ArrayView1<f64>) -> f64, // <- different signature
) -> M {
// initialize array
let mut distances = Array2::zeros((points.nrows(), points.nrows()));
let idx = indices_of(&distances);
// helper function to get the entries of points
let func = |i: usize, j: usize| -> f64 {
dist_fn(&points.slice(s![i, ..]), &points.slice(s![j, ..]))
};
// apply function to matrix with index array in lock-step
par_azip!((c in &mut distances, (i,j) in idx){*c = func(i,j)});
return distances
}

Related

Lifetime of self embedded in Self, not &'a self

Below I have
impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
fn as_poly_iterator(
&self
) -> Result<
which shouldn't need &'a self because the 'a already comes from MyPolynomial<'a, T>. Also, I should pass &'a[T] in PolyIterator::new in the line
let iterator = PolyIterator::new(self.coefficients.as_life_ref());
but I'm getting an error saying that it wants a &'a (dyn Mem<'a, T> + 'a) which I have no idea why.
pub trait Mem<'r, T>
{
fn as_life_ref(&'r self) -> &'r [T];
}
pub struct PolyIterator<'a, T> {
coefficients: &'a [T]
}
impl<'a, T> PolyIterator<'a, T> {
pub fn new(coefficients: &'a[T]) -> PolyIterator<'a, T> {
todo!()
}
}
pub struct MyPolynomial<'a, T> {
coefficients: Box<dyn Mem<'a, T> + 'a>,
}
pub trait AsPolyIterator<'a, T> {
fn as_poly_iterator(&'a self) -> Result<PolyIterator<'a, T>, ()>;
}
impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
fn as_poly_iterator(
&self
) -> Result<
PolyIterator<'a, T>,
(),
> {
let iterator = PolyIterator::new(self.coefficients.as_life_ref());
todo!()
}
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c3e657136252b96cd5aca91efeaea56f
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:31:54
|
31 | let iterator = PolyIterator::new(self.coefficients.as_life_ref());
| ^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/lib.rs:26:3
|
26 | &self
| ^^^^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:31:36
|
31 | let iterator = PolyIterator::new(self.coefficients.as_life_ref());
| ^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src/lib.rs:24:6
|
24 | impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
| ^^
note: ...so that the types are compatible
--> src/lib.rs:31:54
|
31 | let iterator = PolyIterator::new(self.coefficients.as_life_ref());
| ^^^^^^^^^^^
= note: expected `&'a (dyn Mem<'a, T> + 'a)`
found `&(dyn Mem<'a, T> + 'a)`
Your trait definition and implementation do not line up:
pub trait AsPolyIterator<'a, T> {
fn as_poly_iterator(&'a self) -> Result<PolyIterator<'a, T>, ()>;
}
impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
fn as_poly_iterator(&self) -> Result<PolyIterator<'a, T>, ()> { ... }
}
The trait has PolyIterator bound to self, while the implementation has it bound elsewhere, these are not compatible.
It should definitely be &'a self since the PolyIterator is derived from self.coefficients, but you should use a different lifetime 'b for MyPolynomial to avoid over-constraining:
impl<'a, 'b, T> AsPolyIterator<'a, T> for MyPolynomial<'b, T> where 'a: 'b {
fn as_poly_iterator(&'a self) -> Result<PolyIterator<'a, T>, ()> { ... }
}
Mind the where 'a: 'b since that ensures the lifetime 'b is larger than 'a. See it working on the playground.

How do I implement a trait on a curried function?

If I try to implement the trait Frob for functions like foo as follows:
fn foo<'b>(state: &'b mut i32) -> impl FnMut(&str) -> i32 + 'b {
move |i| *state
}
trait Frob<S, I, O> {
fn frob(self, state: &mut S, input: I) -> O;
}
impl<S, I, O, F, G> Frob<S, I, O> for F
where
F: FnMut(&mut S) -> G,
G: FnMut(I) -> O,
{
fn frob(mut self, state: &mut S, input: I) -> O {
self(state)(input)
}
}
fn bar() {
foo.frob(&mut 1, "hi");
}
I get the error
error[E0599]: the method `frob` exists for fn item `for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo}`,
but its trait bounds were not satisfied
...
= note: the following trait bounds were not satisfied:
`<for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo} as FnOnce<(&mut _,)>>::Output = _`
which is required by `for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo}: Frob<_, _, _>`
`<&for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo} as FnOnce<(&mut _,)>>::Output = _`
which is required by `&for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo}: Frob<_, _, _>`
`<&mut for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo} as FnOnce<(&mut _,)>>::Output = _`
which is required by `&mut for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo}: Frob<_, _, _>`
First of all, how do I interpret this error message? Second, how do I write the trait bound correctly? Presumably the problem has something to do with the returned closure hanging on to state, but I can't find a place to specify a lifetime for G.
First of all, how do I interpret this error message?
Yes, it is a tad cryptic isn't it? Two things to recognise:
<for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo} is the compiler's very wordy way of expressing the type of function foo; and
the same note is repeated for that function type, a shared reference to that function type, and a mutable reference to that function type—this happens when the compiler attempts automatic referencing in method call syntax such as you have in foo.frob(...).
So we can quickly distill the error message down to:
error[E0599]: the method `frob` exists for fn item `{foo}`,
but its trait bounds were not satisfied
...
= note: the following trait bounds were not satisfied:
`<{foo} as FnOnce<(&mut _,)>>::Output = _`
which is required by `{foo}: Frob<_, _, _>`
The compiler is telling us that it found a potential frob method on {foo} but in order for it to be applicable, {foo}'s return type must match the constraints of the Frob trait (but it doesn't).
Second, how do I write the trait bound correctly? Presumably the problem has something to do with the returned closure hanging on to state, but I can't find a place to specify a lifetime for G.
You need to add the lifetime constraint to the trait (playground):
trait Frob<'b, S, I, O> {
fn frob(self, state: &'b mut S, input: I) -> O;
}
impl<'b, S: 'b, I, O, F, G> Frob<'b, S, I, O> for F
where
F: FnMut(&'b mut S) -> G,
G: 'b + FnMut(I) -> O,
{
fn frob(mut self, state: &'b mut S, input: I) -> O {
self(state)(input)
}
}

How do I fix the lifetime mismatch when returning a mutable reference to the struct's field from a trait method?

This is my attempt to return a mutable reference to the struct's field.
pub trait Objective {
fn get_children<'a>(&'a mut self) -> &'_ mut Vec<&'_ mut Box<dyn Objective>>;
fn get_parent(&'_ mut self) -> &'_ mut Box<dyn Objective>;
fn update(&'_ self) -> ();
}
// #[derive(Objective)]
pub struct Object<'a> {
children: Vec<&'a mut Box<dyn Objective>>,
parent: &'a mut Box<dyn Objective>,
}
impl<'a> Objective for Object<'a> {
fn get_children(&'a mut self) -> &'_ mut Vec<&'_ mut Box<dyn Objective>> {
return &mut self.children;
}
fn get_parent(&'_ mut self) -> &'_ mut Box<dyn Objective> {
return self.parent;
}
fn update(&'_ self) -> () {}
}
There is a problem with the lifetime. Here is the error given by the compiler:
error[E0308]: method not compatible with trait
--> src/lib.rs:14:5
|
14 | fn get_children(&'a mut self) -> &'_ mut Vec<&'_ mut Box<dyn Objective>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected fn pointer `fn(&'a mut Object<'a>) -> &'a mut std::vec::Vec<&'a mut std::boxed::Box<(dyn Objective + 'static)>>`
found fn pointer `fn(&'a mut Object<'a>) -> &'a mut std::vec::Vec<&'a mut std::boxed::Box<(dyn Objective + 'static)>>`
note: the lifetime `'a` as defined on the method body at 14:5...
--> src/lib.rs:14:5
|
14 | fn get_children(&'a mut self) -> &'_ mut Vec<&'_ mut Box<dyn Objective>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 13:6
--> src/lib.rs:13:6
|
13 | impl<'a> Objective for Object<'a> {
| ^^
error[E0308]: method not compatible with trait
--> src/lib.rs:14:5
|
14 | fn get_children(&'a mut self) -> &'_ mut Vec<&'_ mut Box<dyn Objective>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected fn pointer `fn(&'a mut Object<'a>) -> &'a mut std::vec::Vec<&'a mut std::boxed::Box<(dyn Objective + 'static)>>`
found fn pointer `fn(&'a mut Object<'a>) -> &'a mut std::vec::Vec<&'a mut std::boxed::Box<(dyn Objective + 'static)>>`
note: the lifetime `'a` as defined on the impl at 13:6...
--> src/lib.rs:13:6
|
13 | impl<'a> Objective for Object<'a> {
| ^^
note: ...does not necessarily outlive the lifetime `'a` as defined on the method body at 14:5
--> src/lib.rs:14:5
|
14 | fn get_children(&'a mut self) -> &'_ mut Vec<&'_ mut Box<dyn Objective>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Here is my earlier attempt at this which where I did not explicitly specify the lifetime:
pub trait Objective {
fn get_children(&'_ mut self) -> &'_ mut Vec<&'_ mut Box<dyn Objective>>;
fn get_parent(&'_ mut self) -> &'_ mut Box<dyn Objective>;
fn update(&'_ self) -> ();
}
// #[derive(Objective)]
pub struct Object<'a> {
children: Vec<&'a mut Box<dyn Objective>>,
parent: &'a mut Box<dyn Objective>,
}
impl Objective for Object<'_> {
fn get_children(&'_ mut self) -> &'_ mut Vec<&'_ mut Box<dyn Objective>> {
return &mut self.children;
}
fn get_parent(&'_ mut self) -> &'_ mut Box<dyn Objective> {
return self.parent;
}
fn update(&'_ self) -> () {}
}
And I've gotten a similar error:
error[E0308]: mismatched types
--> src/lib.rs:15:16
|
15 | return &mut self.children;
| ^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected mutable reference `&mut std::vec::Vec<&mut std::boxed::Box<(dyn Objective + 'static)>>`
found mutable reference `&mut std::vec::Vec<&mut std::boxed::Box<(dyn Objective + 'static)>>`
note: the anonymous lifetime #1 defined on the method body at 14:5...
--> src/lib.rs:14:5
|
14 | / fn get_children(&'_ mut self) -> &'_ mut Vec<&'_ mut Box<dyn Objective>> {
15 | | return &mut self.children;
16 | | }
| |_____^
note: ...does not necessarily outlive the lifetime `'_` as defined on the impl at 13:27
--> src/lib.rs:13:27
|
13 | impl Objective for Object<'_> {
| ^^
How do I fix this?
Specify the lifetime on the trait and it works:
pub trait Objective<'a> {
fn get_children(&mut self) -> &mut Vec<&'a mut Box<dyn Objective<'a>>>;
fn get_parent(&mut self) -> &mut Box<dyn Objective<'a>>;
fn update(&self) -> ();
}
// #[derive(Objective)]
pub struct Object<'a> {
children: Vec<&'a mut Box<dyn Objective<'a>>>,
parent: Box<dyn Objective<'a>>,
}
impl<'a> Objective<'a> for Object<'a> {
fn get_children(&mut self) -> &mut Vec<&'a mut Box<dyn Objective<'a>>> {
&mut self.children
}
fn get_parent(&'_ mut self) -> &mut Box<dyn Objective<'a>> {
&mut self.parent
}
fn update(&'_ self) -> () {}
}
By specifying the lifetime on Objective, we can make sure that implementers will return a Vec of mutable references that satisfies the same lifetime requirements as the one needed by the trait.

How can I put an async function into a map in Rust?

I cannot handle async functions when writing an async router for hyper.
This code:
use std::collections::HashMap;
use std::future::Future;
type BoxedResult<T> = Result<T, Box<dyn std::error::Error + Send + Sync>>;
type CalcFn = Box<dyn Fn(i32, i32) -> dyn Future<Output = BoxedResult<i32>>>;
async fn add(a: i32, b: i32) -> BoxedResult<i32> {
Ok(a + b)
}
async fn sub(a: i32, b: i32) -> BoxedResult<i32> {
Ok(a - b)
}
fn main() {
let mut map: HashMap<&str, CalcFn> = Default::default();
map.insert("add", Box::new(add));
map.insert("sub", Box::new(sub));
println!("map size: {}", map.len());
}
Generates the following compiler error:
error[E0271]: type mismatch resolving `<fn(i32, i32) -> impl std::future::Future {add} as std::ops::FnOnce<(i32, i32)>>::Output == dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
--> src/main.rs:17:23
|
17 | map.insert("add", Box::new(add));
| ^^^^^^^^^^^^^ expected opaque type, found trait std::future::Future
|
= note: expected type `impl std::future::Future`
found type `dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
= note: required for the cast to the object type `dyn std::ops::Fn(i32, i32) -> dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
error[E0271]: type mismatch resolving `<fn(i32, i32) -> impl std::future::Future {sub} as std::ops::FnOnce<(i32, i32)>>::Output == dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
--> src/main.rs:18:23
|
18 | map.insert("sub", Box::new(sub));
| ^^^^^^^^^^^^^ expected opaque type, found trait std::future::Future
|
= note: expected type `impl std::future::Future`
found type `dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
= note: required for the cast to the object type `dyn std::ops::Fn(i32, i32) -> dyn std::future::Future<Output = std::result::Result<i32, std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>>`
It seems there is a conflict between impl Future and dyn Future, but I have no idea how to handle it.
This happens because impl Future is a concrete unique type while dyn Future is an abstract type. HashMap expects the abstract type since it can only hold instances of a single type.
If we can box the return type of the async functions, we will able to add these futures into a HashMap.
First we need to change the type of CalcFn:
type CalcFn = Box<dyn Fn(i32, i32) -> Pin<Box<dyn Future<Output = i32>>>>;
Then this can do the trick:
let mut map: HashMap<&str, CalcFn> = Default::default();
map.insert("add", Box::new(|a, b| Box::pin(add(a, b))));
map.insert("sub", Box::new(|a, b| Box::pin(sub(a, b))));
println!("map size: {}", map.len());
//map.get("add").unwrap()(2, 3).await
This complete example
simplified Future's Item type, using an i32 instead of a Result. Please also check the full code for your case.
You can also use types from the futures crate like LocalBoxFuture and BoxFuture created by the FutureExt::boxed and FutureExt::boxed_local methods respectively:
use futures::future::{FutureExt, LocalBoxFuture}; // 0.3.5
use std::collections::HashMap;
type BoxedResult<T> = Result<T, Box<dyn std::error::Error + Send + Sync>>;
type CalcFn = Box<dyn Fn(i32, i32) -> LocalBoxFuture<'static, BoxedResult<i32>>>;
async fn add(a: i32, b: i32) -> BoxedResult<i32> {
Ok(a + b)
}
async fn sub(a: i32, b: i32) -> BoxedResult<i32> {
Ok(a - b)
}
async fn example() {
let mut map: HashMap<&str, CalcFn> = Default::default();
map.insert("add", Box::new(|a, b| add(a, b).boxed()));
map.insert("sub", Box::new(|a, b| sub(a, b).boxed()));
println!("map size: {}", map.len());
//map.get("add").unwrap()(2, 3).await
}

How to use closure instead of trait?

I want to register Gen::my_g as a callback. The simple way is to implement trait Foo for Gen, but I do not want to implement trait Foo for Gen.
In other words, I want to comment out the code marked as B!!! and uncomment the code marked as A!!!.
This is not my code; I can not modify this:
struct S1;
struct TT;
trait MyRes {}
trait Foo {
fn g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a>;
}
impl<F> Foo for F
where
F: for<'a> Fn(&'a mut S1, &[TT]) -> Box<MyRes + 'a>,
{
fn g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a> {
(*self)(ecx, tt)
}
}
fn f1<F>(name: &str, extension: F)
where
F: Foo + 'static,
{
}
This is my code:
struct Gen {}
impl Gen {
fn register(self) {
// f1("aaa", move |ecx, tt| self.my_g(ecx, tt));//A!!!
f1("aaa", self); //B!!!
}
fn my_g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a> {
unimplemented!();
}
}
impl Foo for Gen {
fn g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a> {
self.my_g(ecx, tt)
}
}
If I uncomment //A!!!, the compiler tells me something that I do not understand:
error[E0271]: type mismatch resolving `for<'a, 'r> <[closure#src/main.rs:29:19: 29:52 self:_] as std::ops::FnOnce<(&'a mut S1, &'r [TT])>>::Output == std::boxed::Box<MyRes + 'a>`
--> src/main.rs:29:9
|
29 | f1("aaa", move |ecx, tt| self.my_g(ecx, tt)); //A!!!
| ^^ expected bound lifetime parameter, found concrete lifetime
|
= note: concrete lifetime that was found is lifetime '_#12r
= note: required because of the requirements on the impl of `Foo` for `[closure#src/main.rs:29:19: 29:52 self:_]`
= note: required by `f1`
error[E0281]: type mismatch: `[closure#src/main.rs:29:19: 29:52 self:_]` implements the trait `std::ops::Fn<(&mut S1, &[TT])>`, but the trait `for<'a, 'r> std::ops::Fn<(&'a mut S1, &'r [TT])>` is required
--> src/main.rs:29:9
|
29 | f1("aaa", move |ecx, tt| self.my_g(ecx, tt)); //A!!!
| ^^ --------------------------------- implements `std::ops::Fn<(&mut S1, &[TT])>`
| |
| requires `for<'a, 'r> std::ops::Fn<(&'a mut S1, &'r [TT])>`
| expected concrete lifetime, found bound lifetime parameter
|
= note: required because of the requirements on the impl of `Foo` for `[closure#src/main.rs:29:19: 29:52 self:_]`
= note: required by `f1`
This is a known issue:
Confusing type error due to strange inferred type for a closure argument
The Rust compiler currently cannot infer that a closure is valid for any lifetime (which is what the type of Foo::g requires). It will infer any concrete lifetime, but does not generalize beyond that.

Resources