How to store a list of closures returning a Future and share it between threads in Rust? - rust

I'm trying to write a multi-thread TCP server that can handle multiple connections at the same time with tokio.
I want to structure it in an event-driven way, where it's possible to attach one or more closures to a specific event (like new connection, message received, client disconnected etc).
For example:
server.on_message(|msg: String, stream: &mut TcpStream| {
async move {
println!("Recieved {:?}", msg);
stream.write_all(b"Hello\n").await;
}
}).await;
Every connection will receive its own thread which should have read access to a Vec of callbacks.
pub async fn run(&mut self) {
let listener = TcpListener::bind("127.0.0.1:9090").await.unwrap();
loop {
let (mut socket, _) = listener.accept().await.unwrap();
let cb = self.on_message.clone();
tokio::spawn(async move {
Self::process(socket, cb).await;
});
}
}
Unfortunately, my understanding of Rust is still very rudimentary and I run in circles with:
finding the right type to be stored in Vec
finding the right type for function argument that takes closure callback
Whenever I feel like I make progress in one place then I realise the other got messed up. This is the best I could do but it still doesn't work.
type Callback<T> = dyn Fn(T, &mut TcpStream) -> Pin<Box<dyn Future<Output=()> + Send>> + Send + 'static;
unsafe impl<T> Send for TcpStreamCallbackList<T> {}
unsafe impl<T> Sync for TcpStreamCallbackList<T> {}
impl<T> TcpStreamCallbackList<T> {
pub fn new() -> Self {
Self { callbacks: Vec::new() }
}
pub fn push<G: Send + 'static>(&mut self, mut fun: impl Fn(T, &mut TcpStream) -> G + Send + 'static) where G: Future<Output=()> {
self.callbacks.push(Arc::new(Box::new(move |val:T, stream: &mut TcpStream| Box::pin(fun(val, stream)))));
}
pub async fn call(&self, val: T, stream: &mut TcpStream) where T: Clone {
for cb in self.callbacks.iter() {
let _cb = cb.clone();
_cb(val.clone(), stream).await; // B O O M
}
}
}
The above code doesn't compile until I remove .await on the Future returned by callback in the call function (which defeats the purpose).
error[E0277]: `dyn for<'a> Fn(String, &'a mut tokio::net::TcpStream) -> Pin<Box<dyn futures::Future<Output = ()> + std::marker::Send>> + std::marker::Send` cannot be shared between threads safely
--> src/main.rs:94:26
From what I understand the problem is that the retuned Future is not Send.
note: required by a bound in `tokio::spawn`
--> /Users/lukasz/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.25.0/src/task/spawn.rs:163:21
|
163 | T: Future + Send + 'static,
| ^^^^ required by this bound in `tokio::spawn`
I have no idea if my type makes sense and is thread-safe. I also don't know why the compiler thinks the return type is not Send. I'm really stuck here and would appreciate any help.

I've put together one that is slightly simpler but can be spawned (playground). The key is that Callback needs to be Sync in order for &self to be Send. I tried to use the trick mentioned in this comment, but it doesn't appear to work here, nor does making call take &mut self. I wrote more about Send and Sync on that answer.
use std::future::Future;
use std::pin::Pin;
type CallbackFuture<O> = Pin<Box<dyn Future<Output = O> + Send>>;
type Callback<T> = dyn (Fn(T) -> CallbackFuture<()>) + Send + Sync;
pub struct CallbackList<T> {
list: Vec<Box<Callback<T>>>,
}
impl<T> CallbackList<T> {
pub fn new() -> Self {
Self { list: Vec::new() }
}
pub fn push<F>(&mut self, f: F)
where
F: Fn(T) -> CallbackFuture<()>,
F: Send + Sync + 'static,
{
self.list.push(Box::new(f))
}
pub async fn call(&self, t: T)
where
T: Clone,
{
for f in &self.list {
f(t.clone()).await;
}
}
}
#[tokio::main]
async fn main() {
let mut calls = CallbackList::new();
calls.push(|i| {
Box::pin(async move {
println!("{i}");
})
});
calls.push(|i| {
Box::pin(async move {
println!("{}", i + 1);
})
});
let handle = tokio::spawn(async move {
calls.call(34).await;
});
handle.await.unwrap();
}
I have removed as many trait bounds, 'statics, and wrappers as possible, but you may need to add some back depending on what you do with it. Right now it takes T, but it should be possible to separate that into T and &mut TcpStream. If you update your question with a main function that uses all the elements, I can change mine to match. If all else fails, you can use (_, Arc<Mutex<TcpStream>>) as T.

Related

Rust Dummy Future Value?

I have a use case where I need to specify a dummy Future to make a type concrete. The use case is I have a struct which takes a generic parameter, which is a Future:
let thing = Thing<Fut>::some_method().await?;
some_method is a method on Thing which does not use the Fut at all, but the compiler complains because of the compiler limitations such that the type can't be inferred and is necessary because of the async block.
Since I need a concrete sized thing for Fut, I was hoping there was something in futures_util that I could use. Right now, this is my very bad approach:
use futures::Future;
use std::pin::Pin;
struct Thing<Fut>
where
for<'b> Fut: Future<Output = ()> + Send + 'b,
{
callback: dyn Fn() -> Fut + Send + Sync,
}
impl<Fut> Thing<Fut> where for<'b> Fut: Future<Output = ()> + Send + 'b {
async fn some_method(a: i32) -> Result<(), Box<dyn std::error::Error>> {
println!("I am some_method with value {}", a);
Ok(())
}
}
struct Dummy {
}
impl Future for Dummy {
type Output = ();
fn poll(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
unimplemented!()
}
}
#[tokio::main]
async fn main() {
// this fails
Thing::some_method(3).await.unwrap();
// this works
//Thing::<Dummy>::some_method(3).await.unwrap();
}
Is there something I can leverage here to make such a dummy value available?
Here is a minimal playground example:
playground link
The error:
error[E0698]: type inside `async` block must be known in this context
--> src/main.rs:33:5
|
33 | Thing::some_method(3).await.unwrap();
| ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `Fut`
|
note: the type is part of the `async` block because of this `await`
--> src/main.rs:33:26
|
33 | Thing::some_method(3).await.unwrap();
| ^^^^^^
If you uncomment the success line, it will remove the error.
You can use std::future::Ready (or probably Pending alternatively). This is the type returned by the std::future::ready function.
use std::future::Ready;
type Dummy = Ready<()>;
#[tokio::main]
async fn main() {
Thing::<Dummy>::some_method(3).await.unwrap();
}
But if this function has no dependence on Fut, then I'd question why it's an associated function on Thing in the first place. Maybe it should be a free-standing function instead.

Make returned Future Send if parameters are Send

Can I propagate the Send trait of function parameters to its return type, so that the return type is impl Send if and only if the parameters are?
Details:
An async function has a nice feature. Its returned Future is automatically Send if it can be. In the following example, the async function will create a Future that is Send, if the inputs to the function are Send.
struct MyStruct;
impl MyStruct {
// This async fn returns an `impl Future<Output=T> + Send` if `T` is Send.
// Otherwise, it returns an `impl Future<Output=T>` without `Send`.
async fn func<T>(&self, t: T) -> T {
t
}
}
fn assert_is_send(_v: impl Send) {}
fn main() {
// This works
assert_is_send(MyStruct.func(4u64));
// And the following correctly fails
assert_is_send(MyStruct.func(std::rc::Rc::new(4u64)));
}
playground
Now, I want to move such a function into a trait, which requires using async-trait (which is some codegen that effectively writes my async fn as a function returning Pin<Box<dyn Future>>) or doing something similar manually. Is there a way to write this in a way to retain this auto-Send behavior where the returned Future is made Send if T is Send? The following example implements it as two separate functions:
use std::pin::Pin;
use std::future::Future;
struct MyStruct;
impl MyStruct {
fn func_send<T: 'static + Send>(&self, t: T) -> Pin<Box<dyn Future<Output = T> + Send>> {
Box::pin(async{t})
}
fn func_not_send<T: 'static>(&self, t: T) -> Pin<Box<dyn Future<Output = T>>> {
Box::pin(async{t})
}
}
fn assert_is_send(_v: impl Send) {}
fn main() {
// This works
assert_is_send(MyStruct.func_send(4u64));
// And the following correctly fails
// assert_is_send(MyStruct.func(std::rc::Rc::new(4u64)));
}
playground
But actually, I don't want them to be separate. I want them to be one function similar to how async fn does it automatically. Something along the lines of
use std::pin::Pin;
use std::future::Future;
struct MyStruct;
impl MyStruct {
fn func<T: 'static + ?Send>(&self, t: T) -> Pin<Box<dyn Future<Output = T> + ?Send>> {
Box::pin(async{t})
}
}
fn assert_is_send(_v: impl Send) {}
fn main() {
// This should
assert_is_send(MyStruct.func(4u64));
// And this should fail
assert_is_send(MyStruct.func(std::rc::Rc::new(4u64)));
}
Is something like this possible in Rust? I'm ok with writing the async-trait magic manually and modifying it instead of using the async-trait crate if that is a way to make it work.
Some ideas I had but they haven't really borne fruit yet:
Use min-specialization to specialize on Send? But doesn't seem like that feature is going to be stabilized anytime soon so maybe not the best option.
Return a custom MyFuture type instead of just impl Future and somehow impl Send for MyFuture where T: Send? Would probably be difficult though since I would have to be able to name that Future and async code usually produces impl Future types that cannot be named.
Writing a procedural macro that adds + Send to the return type if it recognizes that the input type is Send. Actually, can procedural macros detect if a certain type implements Send? My guess would be it's not possible since they just work on token streams.
(2) is the only way that could work.
There are two ways to make it work:
Write the future manually, without the help of async and .await. But that means writing the future manually:
enum ConditionalSendFut<T> {
Start { t: T },
Done,
}
impl<T> Unpin for ConditionalSendFut<T> {}
impl<T> Future for ConditionalSendFut<T> {
type Output = T;
fn poll(mut self: Pin<&mut Self>, _context: &mut Context<'_>) -> Poll<Self::Output> {
match &mut *self {
Self::Start { .. } => {
let t = match std::mem::replace(&mut *self, Self::Done) {
Self::Start { t } => t,
_ => unreachable!(),
};
Poll::Ready(t)
}
Self::Done => Poll::Pending,
}
}
}
struct MyStruct;
impl MyStruct {
fn func<T: 'static>(&self, t: T) -> ConditionalSendFut<T> {
ConditionalSendFut::Start { t }
}
}
Playground.
Store a Pin<Box<dyn Future<Output = T>>> and conditionally impl Send on the future. But this requires unsafe code and manually ensuring that you don't hold other non-Send types across .await points:
struct ConditionalSendFut<T>(Pin<Box<dyn Future<Output = T>>>);
// SAFETY: The only non-`Send` type we're holding across an `.await`
// point is `T`.
unsafe impl<T: Send> Send for ConditionalSendFut<T> {}
impl<T> Future for ConditionalSendFut<T> {
type Output = T;
fn poll(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
self.0.as_mut().poll(context)
}
}
struct MyStruct;
impl MyStruct {
fn func<T: 'static>(&self, t: T) -> ConditionalSendFut<T> {
ConditionalSendFut(Box::pin(async { t }))
}
}
Playground.
(1) cannot work with traits, as each impl will have a different future. This leaves us with (2) only. I would not recommend it, but it is possible.
It is very likely that when async fns in traits will be stable there will be a mechanism to that (what is talked about currently is to impl them conditionally and use bounds on use sites to require them) but currently there is no such thing, even on the nightly implementation of async fns in traits.

Could not store async function in a struct field in Rust

I have a struct Task which is defined as below:
pub struct Task<F>
where
F: Future<Output = ()>,
{
pub name: &'static str,
pub should_run_late: bool,
pub time: Time,
runner: fn() -> F,
}
impl<F> Task<F>
where
F: Future<Output = ()>,
{
pub async fn run(self) {
(self.runner)().await;
}
pub fn set_Runner(&mut self, func: fn() -> F)
{
self.runner = func;
}
}
and call it this way
tokio::spawn(async move {
task.run().await;
});
I'm putting Tasks in a vector in some struct like this:
some struct {
pub tasks: HashMap<String, HashMap<String, Vec<Task<dyn Future<Output = ()>>>>>
}
The problem is in the above which says it doesn't implement Sized trait and when then wrapped it with Box:
HashMap<String, HashMap<String, Vec<Task<Box<dyn Future<Output = ()>>>>>>
It says to use Box::pin.
It really makes everything confusing.
I'm fairly new in rust, and what ever I try I can't make it.
Changing the type of the F parameter in the Vec<Task<F>> won't help, since as written, F must match the actual return type of the runner function. You need to handle the function “dynamically” too, not just the future. Once you do, the code can also be simplified. Here's a new definition of Task:
pub struct Task {
pub name: &'static str,
pub should_run_late: bool,
pub time: Time,
runner: Box<dyn FnOnce() -> Pin<Box<dyn Future<Output = ()> + Send>> + Send>,
}
Notice that the stored function returns Pin<Box<dyn Future>>, so we need to wrap the function when it's stored by set_runner. (This is going to match the Box::pin() that you noticed being asked for.) Actually running the task is the same:
impl Task {
pub async fn run(self) {
(self.runner)().await;
}
pub fn set_runner<Func, Fut>(&mut self, func: Func)
where
Func: Send + 'static + FnOnce() -> Fut,
Fut: Send + 'static + Future<Output = ()>,
{
self.runner = Box::new(move || Box::pin(func()));
}
}
I generalized the func parameter so it will accept closures and not just function pointers — since we're boxing the function anyway, this is free.
Compilable sample on Rust Playground
Now, this code can be a bit messy to read. There are a couple of libraries providing trait aliases which can help you out by removing the boilerplate. The futures library contains futures::future::BoxFuture which tidies up storing a boxed future:
use futures::future::BoxFuture;
pub struct Task {
...
runner: Box<dyn FnOnce() -> BoxFuture<'static, ()> + Send>,
}
For the input to set_runner, the two lines of trait bounds are just saying "Func is an async function which takes no arguments and returns ()". We can simplify that (somewhat) using async_fn_traits:
use async_fn_traits::AsyncFnOnce0;
impl Task {
...
pub fn set_runner<F>(&mut self, func: F)
where
F: AsyncFnOnce0<Output = ()> + Send + 'static,
F::OutputFuture: Send + 'static,
{
self.runner = Box::new(move || Box::pin(func()));
}
}
In situations that don't involve storing the future this would be even more of an improvement (because we would not need to write out the Send + 'static bounds), but at least here we avoid needing the separate Fut type parameter which can't actually vary independently.
Using these aliases is entirely optional — it's up to you which version of the code you think is clearer. For what it's worth, futures is quite commonly used for other future-related utilities, and async_fn_traits is considerably more obscure.

How do I use an higher order async function to filter a Vec?

Filtering via async predicate, the "easy" way
One way would be to join_all!() the Futures that compute the filters on every item. And then filters synchronously based on those:
let arr = vec![...]
let filters = join_all!(arr.iter().map(|it| async { predicate(it).await })
let filtered = arr.enumerate().filter(|index, item| filters[index]).collect::<Vec<_>>();
However, exploring Rust, there's a cleaner way via futures::stream::iter iterators:
let filtered = futures::stream::iter(vec![...])
.filter(|item| async { predicate(item).await })
.collect::<Vec<_>>
.await
All good up to now.
Configurable filter: trouble begins
What if we want to use a functional API to make the predicate easily configurable?
In that case, our calls will look like:
let filtered = futures::stream::iter(vec![...])
.filter(by_length(4)) // neat!
.collect::<Vec<_>>
.await
And the predicate:
fn by_length(min_length: usize) -> impl FnMut(&i32) -> Future<Output = bool> {
|n| async { query_length(n).await > min_length }
}
async fn query_length(n: &i32) -> usize {
// pretend we're making a network request to fetch `len`...
// for easy reproducibility's sake this will work here
n.to_string().len()
}
Unfortunately compiler is not happy anymore: it complains the Future needs dyn keyword. And, after adding dyn, it complains it's not Sized, as in this minimal reproduction:
use futures::future::Future;
#[tokio::main]
async fn main() {
let arr = vec![10, 100, 1000];
let filtered = futures::stream::iter(arr.into_iter())
.filter(by_length(3))
.collect::<Vec<_>>()
.await;
println!("{:?}", filtered); // should print [100, 1000]
}
fn by_length(min_length: usize) -> impl FnMut(&i32) -> Future<Output = bool> {
|n| async { query_length(n).await > min_length }
}
// yeah it doesn't need to be async in this case, but let's pretend
async fn query_length(n: &i32) -> usize {
n.to_string().len()
}
The error:
Compiling playground v0.0.1 (/playground)
error[E0277]: the size for values of type `(dyn futures::Future<Output = bool> + 'static)` cannot be known at compilation time
--> src/main.rs:16:9
|
16 | |n| async { query_length(n).await > min_length }
| ^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `(dyn futures::Future<Output = bool> + 'static)`
= note: the return type of a function must have a statically known size
Questions
So how can the filter predicate be made configurable?
From what I gather, the dyn keyword requested by the compiler here is to make it explicit it will rely automatic dispatch, incurring in additional overhead.
However we only need a single typed case here, for which we should be able to generate inline-able machine code. How can Rust be instructed to do that?
While you can't return an impl Future from an impl FnMut, you can return a boxed future, i.e. a dyn Future which must be boxed because it's in return position. After a bit of borrow checker tetris, we arrive to this:
fn by_length(min_length: usize) -> impl FnMut(&i32) -> Pin<Box<dyn Future<Output = bool>>> {
move |&n| Box::pin(async move { query_length(&n).await > min_length })
}
Playground
However we only need a single typed case here, for which we should be able to generate inline-able machine code. How can Rust be instructed to do that?
I don't think that's currently possible, at least not if you're invoking an async fn like query_length(). Consider a manually written implementation:
fn by_length(min_length: usize) -> impl FnMut(&i32) -> ByLength {
move |&n| ByLength { n }
}
Now, how do we define ByLength? It must implement Future, and its poll() simply transmits the result of polling query_length(n). But the future returned by query_length(n) could suspend multiple times, so ByLength must store the future so it can poll it as many times as needed - for example:
struct ByLength {
n: i32,
query_fut: Option<???>,
}
impl Future for ByLength {
type Output = usize;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<usize> {
if self.query_fut.is_none() {
self.query_fut = Some(query_length(self.n));
}
self.query_fut.unwrap().poll(cx)
}
}
But now the problem becomes apparent: there is no type to substitute for ??? because query_length() is an async function which returns a future of an anonymous type. Making ByLength generic doesn't work because then we're back at the problem that a closure can't return a generic type that it provides. The signature we'd like would require higher-kinded types:
fn by_length(min_length: usize) -> impl for<T> FnMut(&i32) -> ByLength<T> {
move |&n| ByLength { n }
}
...but if we had that, we could just use query_length() directly:
fn by_length(min_length: usize) -> impl for<T: Future<Output = usize>> FnMut(&i32) -> T {
move |&n| async move { by_length(&n) }
}

Creating a stream of values while calling async fns?

I can't figure out how to provide a Stream where I await async functions to get the data needed for the values of the stream.
I've tried to implement the the Stream trait directly, but I run into issues because I'd like to use async things like awaiting, the compiler does not want me to call async functions.
I assume that I'm missing some background on what the goal of Stream is and I'm just attacking this incorrectly and perhaps I shouldn't be looking at Stream at all, but I don't know where else to turn. I've seen the other functions in the stream module that could be useful, but I'm unsure how I could store any state and use these functions.
As a slightly simplified version of my actual goal, I want to provide a stream of 64-byte Vecs from an AsyncRead object (i.e. TCP stream), but also store a little state inside whatever logic ends up producing values for the stream, in this example, a counter.
pub struct Receiver<T>
where
T: AsyncRead + Unpin,
{
readme: T,
num: u64,
}
// ..code for a simple `new() -> Self` function..
impl<T> Stream for Receiver<T>
where
T: AsyncRead + Unpin,
{
type Item = Result<Vec<u8>, io::Error>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let mut buf: [u8; 64] = [0; 64];
match self.readme.read_exact(&mut buf).await {
Ok(()) => {
self.num += 1;
Poll::Ready(Some(Ok(buf.to_vec())))
}
Err(e) => Poll::Ready(Some(Err(e))),
}
}
}
This fails to build, saying
error[E0728]: `await` is only allowed inside `async` functions and blocks
I'm using rustc 1.36.0-nightly (d35181ad8 2019-05-20) and my Cargo.toml looks like this:
[dependencies]
futures-preview = { version = "0.3.0-alpha.16", features = ["compat", "io-compat"] }
pin-utils = "0.1.0-alpha.4"
Answer copy/pasted from the reddit post by user Matthias247:
It's unfortunately not possible at the moment - Streams have to be implemented by hand and can not utilize async fn. Whether it's possible to change this in the future is unclear.
You can work around it by defining a different Stream trait which makes use of Futures like:
trait Stream<T> {
type NextFuture: Future<Output=T>;
fn next(&mut self) -> Self::NextFuture;
}
This article and this futures-rs issue have more information around it.
You can do it with gen-stream crate:
#![feature(generators, generator_trait, gen_future)]
use {
futures::prelude::*,
gen_stream::{gen_await, GenTryStream},
pin_utils::unsafe_pinned,
std::{
io,
marker::PhantomData,
pin::Pin,
sync::{
atomic::{AtomicU64, Ordering},
Arc,
},
task::{Context, Poll},
},
};
pub type Inner = Pin<Box<dyn Stream<Item = Result<Vec<u8>, io::Error>> + Send>>;
pub struct Receiver<T> {
inner: Inner,
pub num: Arc<AtomicU64>,
_marker: PhantomData<T>,
}
impl<T> Receiver<T> {
unsafe_pinned!(inner: Inner);
}
impl<T> From<T> for Receiver<T>
where
T: AsyncRead + Unpin + Send + 'static,
{
fn from(mut readme: T) -> Self {
let num = Arc::new(AtomicU64::new(0));
Self {
inner: Box::pin(GenTryStream::from({
let num = num.clone();
static move || loop {
let mut buf: [u8; 64] = [0; 64];
match gen_await!(readme.read_exact(&mut buf)) {
Ok(()) => {
num.fetch_add(1, Ordering::Relaxed);
yield Poll::Ready(buf.to_vec())
}
Err(e) => return Err(e),
}
}
})),
num,
_marker: PhantomData,
}
}
}
impl<T> Stream for Receiver<T>
where
T: AsyncRead + Unpin,
{
type Item = Result<Vec<u8>, io::Error>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.inner().poll_next(cx)
}
}

Resources