How to replace combinators with Future?

I have a function which returns Future. It accepts another function which accepts one argument and returns Future. Second function can be implemented as combinators chain passed into first function. It looks like this:

use bb8::{Pool, RunError};
use bb8_postgres::PostgresConnectionManager;
use tokio_postgres::{error::Error, Client, NoTls};

#[derive(Clone)]
pub struct DataManager(Pool<PostgresConnectionManager<NoTls>>);

impl DataManager {
    pub fn new(pool: Pool<PostgresConnectionManager<NoTls>>) -> Self {
        Self(pool)
    }

    pub fn create_user(
        &self,
        reg_req: UserRequest,
    ) -> impl Future<Item = User, Error = RunError<Error>> {
        let sql = "long and awesome sql";

        let query = move |mut conn: Client| {  // function which accepts one argument and returns Future
            conn.prepare(sql).then(move |r| match r {
                Ok(select) => {
                    let f = conn
                        .query(&select, &[&reg_req.email, &reg_req.password])
                        .collect()
                        .map(|mut rows| {
                            let row = rows.remove(0);
                            row.into()
                        })
                        .then(move |r| match r {
                            Ok(v) => Ok((v, conn)),
                            Err(e) => Err((e, conn)),
                        });
                    Either::A(f)
                }
                Err(e) => Either::B(future::err((e, conn))),
            })
        };
        self.0.run(query)  // function which returns Future and accepts another function
    }
}

But I want to write code of create_user as a struct implementing Future.

struct UserCreator(Pool<PostgresConnectionManager<NoTls>>, UserRequest);

impl UserCreator {
    fn new(pool: Pool<PostgresConnectionManager<NoTls>>, reg_req: UserRequest) -> Self {
        Self(pool, reg_req)
    }
}

How to implement Future for this struct that works as first function? Please help me with an example.

Now I tried to make it like this, but nothing is computed and execution always blocks.

impl Future for UserCreator {
    type Item = User;
    type Error = RunError<Error>;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        // Code which which works like `DataManager.create_user`
        let sql = "long and awesome sql";
        let reg_req = &self.1;

        let query = move |mut conn: Client| {
            conn.prepare(sql).then(move |r| match r {
                Ok(select) => {
                    let f = conn
                        .query(&select, &[&reg_req.email, &reg_req.password])
                        .collect()
                        .map(|mut rows| {
                            let row = rows.remove(0);
                            row.into()
                        })
                        .then(move |r| match r {
                            Ok(v) => Ok((v, conn)),
                            Err(e) => Err((e, conn)),
                        });
                    Either::A(f)
                }
                Err(e) => Either::B(future::err((e, conn))),
            })
        };
        self.0.run(query).poll()
    }
}

Futures are always lazy. It should register itself to the event loop if not succeed at first try, to let executor know when to try it again. And most importantly in this case, It should cancel itself on drop.

Assuming the future returned by .run(query) is well-implemented, it should cancel itself as it will be dropped at the end of this poll(). So you should store the future somewhere and reuse it until it makes success(or fail).

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.