Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make prepare() return a Future that satisfies Send. #477

Merged
merged 1 commit into from
Sep 4, 2019
Merged

Make prepare() return a Future that satisfies Send. #477

merged 1 commit into from
Sep 4, 2019

Conversation

jebrosen
Copy link
Contributor

@jebrosen jebrosen commented Sep 4, 2019

Currently this code:

use futures::{FutureExt, TryStreamExt};
use tokio_postgres::{Error, NoTls};

async fn example() -> Result<(), Error> {
    let (mut client, connection) = tokio_postgres::connect("host=localhost user=postgres password=postgres", NoTls).await?;

    let connection = connection.map(|r| {
        if let Err(e) = r {
            eprintln!("connection error: {}", e);
        }
    });
    tokio::spawn(connection);

    let stmt = client.prepare("SELECT $1::TEXT").await?;

    let rows = client
        .query(&stmt, &[&"hello world"])
        .try_collect::<Vec<_>>()
        .await?;

    // Now we can check that we got back the same string we sent over.
    let value: &str = rows[0].get(0);

    assert_eq!(value, "hello world");

    Ok::<(), Error>(())
}

#[tokio::main]
async fn main() {
    example().boxed().await.unwrap()
}

Fails with the following error:

    Checking rocket-tokio-postgres v0.1.0 (/home/jeb/code/tokio-postgres-prepare-send)
error[E0277]: `dyn tokio_postgres::types::ToSql` cannot be shared between threads safely
  --> src/main.rs:31:15
   |
31 |     example().boxed().await.unwrap()
   |               ^^^^^ `dyn tokio_postgres::types::ToSql` cannot be shared between threads safely
   |
   = help: the trait `std::marker::Sync` is not implemented for `dyn tokio_postgres::types::ToSql`
   = note: required because of the requirements on the impl of `std::marker::Send` for `&dyn tokio_postgres::types::ToSql`
   = note: required because it appears within the type `[&dyn tokio_postgres::types::ToSql; 1]`
   = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12> {&'r std::sync::Arc<tokio_postgres::client::InnerClient>, u32, fn(std::result::Result<tokio_postgres::statement::Statement, tokio_postgres::error::Error>) -> std::result::Result<<std::result::Result<tokio_postgres::statement::Statement, tokio_postgres::error::Error> as std::ops::Try>::Ok, <std::result::Result<tokio_postgres::statement::Statement, tokio_postgres::error::Error> as std::ops::Try>::Error> {<std::result::Result<tokio_postgres::statement::Statement, tokio_postgres::error::Error> as std::ops::Try>::into_result}, impl core::future::future::Future, (), tokio_postgres::statement::Statement, [&'t0 (dyn tokio_postgres::types::ToSql + 't1); 1], &'t2 [&'t3 (dyn tokio_postgres::types::ToSql + 't4)], std::result::Result<std::vec::Vec<u8>, tokio_postgres::error::Error>, impl futures_core::stream::Stream, std::pin::Pin<&'t5 mut impl futures_core::stream::Stream>, fn(std::result::Result<std::option::Option<tokio_postgres::row::Row>, tokio_postgres::error::Error>) -> std::result::Result<<std::result::Result<std::option::Option<tokio_postgres::row::Row>, tokio_postgres::error::Error> as std::ops::Try>::Ok, <std::result::Result<std::option::Option<tokio_postgres::row::Row>, tokio_postgres::error::Error> as std::ops::Try>::Error> {<std::result::Result<std::option::Option<tokio_postgres::row::Row>, tokio_postgres::error::Error> as std::ops::Try>::into_result}, futures_util::try_stream::try_next::TryNext<'t6, std::pin::Pin<&'t7 mut impl futures_core::stream::Stream>>, tokio_postgres::row::Row, std::string::String, i8, std::option::Option<u32>, bool, fn(std::result::Result<std::vec::Vec<std::string::String>, tokio_postgres::error::Error>) -> std::result::Result<<std::result::Result<std::vec::Vec<std::string::String>, tokio_postgres::error::Error> as std::ops::Try>::Ok, <std::result::Result<std::vec::Vec<std::string::String>, tokio_postgres::error::Error> as std::ops::Try>::Error> {<std::result::Result<std::vec::Vec<std::string::String>, tokio_postgres::error::Error> as std::ops::Try>::into_result}, impl core::future::future::Future, fn(std::result::Result<tokio_postgres::types::Type, tokio_postgres::error::Error>) -> std::result::Result<<std::result::Result<tokio_postgres::types::Type, tokio_postgres::error::Error> as std::ops::Try>::Ok, <std::result::Result<tokio_postgres::types::Type, tokio_postgres::error::Error> as std::ops::Try>::Error> {<std::result::Result<tokio_postgres::types::Type, tokio_postgres::error::Error> as std::ops::Try>::into_result}, std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<tokio_postgres::types::Type, tokio_postgres::error::Error>> + 't9)>>, std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<tokio_postgres::types::Type, tokio_postgres::error::Error>> + 't10)>>, fn(std::result::Result<std::vec::Vec<tokio_postgres::types::Field>, tokio_postgres::error::Error>) -> std::result::Result<<std::result::Result<std::vec::Vec<tokio_postgres::types::Field>, tokio_postgres::error::Error> as std::ops::Try>::Ok, <std::result::Result<std::vec::Vec<tokio_postgres::types::Field>, tokio_postgres::error::Error> as std::ops::Try>::Error> {<std::result::Result<std::vec::Vec<tokio_postgres::types::Field>, tokio_postgres::error::Error> as std::ops::Try>::into_result}, impl core::future::future::Future, std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<tokio_postgres::types::Type, tokio_postgres::error::Error>> + 't12)>>}`

(clipped, the rest is at https://paste.rs/sB1)

The same example works as intended after this PR.

I understand why the change to get_type_rec was necessary, but I think the changes to params are necessary because of a bug in rustc - possibly rust-lang/rust#59087 or similar.

@sfackler
Copy link
Owner

sfackler commented Sep 4, 2019

Thanks! I'll add some tests ensuring that all of our futures stay Send where needed.

@sfackler sfackler merged commit 54e52bd into sfackler:std-futures Sep 4, 2019
@jebrosen jebrosen deleted the prepare-send branch December 1, 2019 22:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants