Reputation: 2039
Is there any way to use futures in callbacks? For example...
// Send message on multiple channels while removing ones that are closed.
use smol::channel::Sender;
...
// (expecting bool, found opaque type)
vec_of_sender.retain( |sender| async {
sender.send(msg.clone()).await.is_ok()
});
My work-around is to loop twice: On the first pass I delete closed senders (non-async) and on the second I do the actual send (async using for sender in ...
). But it seems like I should be able to do it all in a single retain()
call.
Upvotes: 2
Views: 2052
Reputation: 14676
To avoid creating a new Vec
, you can also use swap_remove
:
let mut i = 0usize;
while i < vec_of_sender.len() {
if vec_of_sender[i].send(msg.clone()).await.is_ok() {
i += 1;
} else {
vec_of_sender.swap_remove(i);
}
}
Note that this will change the order of the vector.
Upvotes: 0
Reputation: 13518
The closure passed to retain
must return a bool
, but every async
function returns impl Future
. Instead, you can use Stream
, which is the asynchronous version of Iterator
. You can convert the vector into a Stream
:
let stream = stream::iter(vec_of_sender);
And then use the filter
method, which accepts an asynchronous closure and returns a new Stream
:
let vec_of_sender = stream.filter(|sender| async {
sender.send(msg.clone()).await.is_ok()
}).collect::<Vec<Sender>>();
Upvotes: 1
Reputation: 58735
You can't use retain
in this way. The closure that retain
accepts must implement FnMut(&T) -> bool
, but every async
function returns an implementation of Future
.
You can turn an async function into a synchronous one by blocking on it. For example, if you were using tokio
, you could do this:
use tokio::runtime::Runtime;
let rt = Runtime::new().unwrap();
vec_of_sender.retain(|sender| {
rt.block_on(async { sender.send().await.is_ok() })
});
However, there is overhead to adding an async runtime, and I have a feeling that you are trying to solve the wrong problem.
Upvotes: 1