Converting`async fn` in public traits to `impl Future>> + Send;`

⚓ Rust    📅 2025-09-29    👤 surdeus    👁️ 6      

surdeus

Warning

This post was published 32 days ago. The information described in this article may have changed.

Originally, I have Playground 1

pub trait Import {
    async fn sql_import() -> Result<(), Box<dyn Error>>;

    async fn import() -> Result<(), Box<dyn Error>>
    where
        Self: DeserializeOwned,
    {
        Self::sql_import().await?;

        Ok(())
    }
}

And of course I got a warning about the two async fns in the trait and suggested to do

-     async fn sql_import() -> Result<(), Box<dyn Error>>;
+     fn sql_import() -> impl Future<Output = Result<(), Box<dyn Error>>> + Send;

If I follow the instructions Playground 2, I got an error

error: future cannot be sent between threads safely
  --> src/lib.rs:28:5
   |
28 |     async fn sql_import() -> Result<(), Box<dyn Error>> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `sql_import` is not `Send`
   |
   = help: within `IntoChunks<std::ops::Range<i32>>`, the trait `Sync` is not implemented for `RefCell<GroupInner<usize, Range<i32>, ChunkIndex>>`
   = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
note: future is not `Send` as this value is used across an await
  --> src/lib.rs:30:36
   |
29 |         for _chunk in (0..2).chunks(1).into_iter() {
   |                       ---------------------------- has type `itertools::Chunks<'_, std::ops::Range<i32>>` which is not `Send`
30 |             execute_unprepared("").await?;
   |                                    ^^^^^ await occurs here, with `(0..2).chunks(1).into_iter()` maybe used later
note: required by a bound in `Import::sql_import::{anon_assoc#0}`
  --> src/lib.rs:12:88
   |
12 |     fn sql_import() -> impl std::future::Future<Output = Result<(), Box<dyn Error>>> + Send;

It turns out adding Send(suggested by the compilter) to the return causes troubles.

Questions

  1. Is async fn sql_import() -> Result<(), Box<dyn Error>>; the same as
    a) fn sql_import() -> impl Future<Output = Result<(), Box<dyn Error>>>; or
    b) fn sql_import() -> impl Future<Output = Result<(), Box<dyn Error>>> + Send;
  2. I don't understand why adding Send suddenly breaks, i.e. I cannot comprehend what the compiler tries to tell me. Why is it related to itertools::Chunks<..>?

4 posts - 4 participants

Read full topic

🏷️ Rust_feed