async-stream icon indicating copy to clipboard operation
async-stream copied to clipboard

try_stream is !Send with ? and MutexGuard or try-block

Open elbaro opened this issue 4 years ago • 2 comments
trafficstars

  1. MutexGuard
try_stream! {
  {
    let _guard = mutex.try_lock().unwrap();
    Err(200)?;
  }
  {
    yield 100;
  }
}

Err(200)? is expanded by try_stream! to something like __yield_tx.send(::core::result::Result::Err(200).await; This makes the stream !Send.

note: future is not `Send` as this value is used across an await

This can be fixed if async-stream captures the error and tx.send in the outermost block.

let result = Result<_,_> = || {
 .. user code ..
};
match result {
  Ok(..) => ..
  Err(err) => __yield_tx.send(..).await;
}
  1. try-block

A workaround is to capture the error in result: Result<..> and emit the error after MutexGuard is dropped. However, async-stream does not recognize ? in try-blocks.

try_stream! {
  let result = {
    let _guard = mutex.try_lock().unwrap();
    let result: Result<..> = try {
          Err(200)?; // async-stream expands this to `tx.send(..)`.
          Ok(())
    };
    result
  };
  result?;
  {
    yield 100;
  }
}

elbaro avatar Nov 21 '21 10:11 elbaro

Is this an std::sync::Mutex? The guards on those are not send. If you need to hold a mutex guard over an await boundary, use tokio::sync::Mutex.

Noah-Kennedy avatar Nov 25 '21 19:11 Noah-Kennedy

crossbeam Mutex is used because I know try_lock() always succeeds in my case and it probably has lower latency than async version.

The issue is that I didn't use the object over an await boundary but try_stream! macro did.

elbaro avatar Nov 26 '21 04:11 elbaro