I do a server update in rust. it create patches between 2 binaries files, and serves static files
I try to do
let mut update_state;
if let Some(state) = update_stream.next().await {
if let Ok(state) = state {
update_state = state
} else if let Err(err) = state {
reply = BuildOutput { error: "Update failed: ".to_string() + &err.to_string() }
}
} else {
reply = BuildOutput { error: "Unreacheable".to_string() }
}
let state = update_state.borrow();
let progress = state.histogram.progress();
let res = update_stream.try_for_each(|_state| future::ready(Ok(()))).await;
but get
note: future is not `Send` as this value is used across an await
--> server\grpc\src\rpc.rs:260:50
|
259 | let mut update_state;
| ---------------- has type `SharedUpdateProgress` which is not `Send`
260 | if let Some(state) = update_stream.next().await {
| ^^^^^^ await occurs here, with `mut update_state` maybe used later
...
305 | }
| - `mut update_state` is later dropped here
= note: required for the cast from `impl futures::Future<Output = Result<tonic::Response<BuildOutput>, Status>>` to the object type `dyn futures::Future<Output = Result<tonic::Response<BuildOutput>, Status>> + std::marker::Send
SharedUpdateProgress:
#[derive(Clone)]
pub struct SharedUpdateProgress {
state: Rc<RefCell<UpdateProgress>>,
}
impl SharedUpdateProgress {
pub fn new(target_revision: CleanName) -> Self {
Self { state: Rc::new(RefCell::new(UpdateProgress::new(target_revision))) }
}
pub fn borrow(&self) -> Ref<'_, UpdateProgress> {
self.state.borrow()
}
pub(crate) fn borrow_mut(&self) -> RefMut<'_, UpdateProgress> {
self.state.borrow_mut()
}
}
I don't know why and don't know how to fix it
I assume a minimal reproducible example of your problem is as follows:
use std::{cell::RefCell, rc::Rc};
use tokio::time::{sleep, Duration};
#[derive(Clone)]
pub struct SharedString {
state: Rc<RefCell<String>>,
}
impl SharedString {
pub fn new(initial: &str) -> Self {
Self {
state: Rc::new(RefCell::new(initial.into())),
}
}
}
async fn run() {
let shared_string = SharedString::new("Hello,");
sleep(Duration::from_millis(1)).await;
*shared_string.state.borrow_mut() += " world!";
sleep(Duration::from_millis(1)).await;
println!("{:?}", shared_string.state.borrow());
}
#[tokio::main]
async fn main() {
tokio::task::spawn(run()).await.unwrap();
}
error: future cannot be sent between threads safely
--> src/main.rs:27:24
|
27 | tokio::task::spawn(run()).await.unwrap();
| ^^^^^ future returned by `run` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<RefCell<String>>`
note: future is not `Send` as this value is used across an await
--> src/main.rs:19:36
|
18 | let shared_string = SharedString::new("Hello,");
| ------------- has type `SharedString` which is not `Send`
19 | sleep(Duration::from_millis(1)).await;
| ^^^^^^ await occurs here, with `shared_string` maybe used later
...
23 | }
| - `shared_string` is later dropped here
note: required by a bound in `tokio::spawn`
--> /home/martin/.cargo/git/checkouts/tokio-dd4afa005f1f4b79/686577b/tokio/src/task/spawn.rs:163:21
|
163 | T: Future + Send + 'static,
| ^^^^ required by this bound in `tokio::spawn`
The tokio Runtime is usually multi-threaded, meaning that at any .await point your task could get moved from one thread to another. That's why everything that is held across an .await point must be Send. Which Rc<RefCell<>> is explicitely not, because it's a single-threaded reference counter.
Solution: Replace Rc<RefCell<>> with Arc<Mutex<>>, which is the thread-safe equivalent.
use std::sync::{Arc, Mutex};
use tokio::time::{sleep, Duration};
#[derive(Clone)]
pub struct SharedString {
state: Arc<Mutex<String>>,
}
impl SharedString {
pub fn new(initial: &str) -> Self {
Self {
state: Arc::new(Mutex::new(initial.into())),
}
}
}
async fn run() {
let shared_string = SharedString::new("Hello,");
sleep(Duration::from_millis(1)).await;
*shared_string.state.lock().unwrap() += " world!";
sleep(Duration::from_millis(1)).await;
println!("{:?}", shared_string.state.lock().unwrap());
}
#[tokio::main]
async fn main() {
tokio::task::spawn(run()).await.unwrap();
}
"Hello, world!"
Related
I'm using the below code in my real project. (Obviously this is simplified and one file only for playground.)
Rust explorer playground
As you can see I'm trying to use a sqlx Transaction from one function to a closure.
But I'm stucked.
I don't even know if this (so common Golang pattern) is the best wat to do in Rust. But at least it should work now.
use std::{future::Future, pin::Pin, sync::Arc};
pub trait Trait: Send + Sync + Player + Shirt {}
impl<T: Player + Shirt> Trait for T {}
pub type Lambda<'a, ArgT, ResT> =
dyn Fn(ArgT) -> Pin<Box<dyn Future<Output = Result<ResT, String>> + Send + 'a>> + Sync + 'a;
#[async_trait::async_trait]
pub trait Player: Send + Sync {
async fn player_create<'a>(
&'a self,
_input: &PlayerInput,
lambda: &Lambda<'_, PlayerCreateLambdaArgs<'a>, DomainPlayer>,
) -> Result<DomainPlayer, String>;
}
#[async_trait::async_trait]
pub trait Shirt: Send + Sync {
async fn shirt_get_next_and_increase<'a>(
&'a self,
tx: &'a mut sqlx::PgConnection,
model: String,
) -> Result<i64, String>;
}
pub struct Repo {
pub pool: Arc<sqlx::PgPool>,
}
impl Repo {
pub fn new(pool: Arc<sqlx::PgPool>) -> Self {
Self { pool }
}
}
#[async_trait::async_trait]
impl Player for Repo {
async fn player_create<'a>(
&'a self,
_input: &PlayerInput,
lambda: &Lambda<'_, PlayerCreateLambdaArgs<'a>, DomainPlayer>,
) -> Result<DomainPlayer, String> {
let mut tx = self.pool.begin().await.unwrap();
// use _input here
let shirt_next_value = Box::new(|model: String| {
self::Shirt::shirt_get_next_and_increase(self, &mut tx, model)
});
let domain_player = lambda(PlayerCreateLambdaArgs { shirt_next_value }).await?;
let res =
sqlx::query_as::<_, DomainPlayer>("INSERT INTO player (...) VALUES (...) RETURNING *")
.bind(domain_player.id)
.bind(domain_player.shirt_number)
.fetch_one(&mut *tx)
.await
.unwrap();
Ok(res)
}
}
#[async_trait::async_trait]
impl Shirt for Repo {
async fn shirt_get_next_and_increase<'a>(
&'a self,
_tx: &'a mut sqlx::PgConnection,
_model: String,
) -> Result<i64, String> {
// Here I'm awaiting an async call for DB operations using the same DB transacion of the caller (_tx)...
// use _tx here...
let res = 123;
Ok(res)
}
}
pub struct Needs {
pub command_pg_repo: Arc<dyn Trait>,
}
#[derive(Default)]
pub struct PlayerInput {
pub id: String,
}
#[derive(Debug, Default, Clone, sqlx::FromRow)]
pub struct DomainPlayer {
pub id: String,
pub shirt_number: i64,
}
pub struct PlayerCreateLambdaArgs<'a> {
// other needed fields here
pub shirt_next_value: Box<
dyn FnMut(String) -> Pin<Box<dyn Future<Output = Result<i64, String>> + Send + 'a>>
+ Send
+ Sync
+ 'a,
>,
}
pub struct Handler {
needs: Arc<Needs>,
}
impl Handler {
pub fn new(needs: Arc<Needs>) -> Self {
Self { needs }
}
pub async fn handle(&self, input: &PlayerInput) -> Result<DomainPlayer, String> {
let res = self
.needs
.command_pg_repo
.player_create(&input, &|mut args| {
let input = input;
Box::pin(async move {
let shirt_number = (args.shirt_next_value)("player".to_string()).await?;
let o = DomainPlayer {
id: input.id.to_string(),
shirt_number,
};
Ok(o)
})
})
.await?;
Ok(res)
}
}
#[tokio::main]
async fn main() -> Result<(), String> {
let db_conn = sqlx::PgPool::connect("fake_url").await.unwrap();
let pg_repo = Arc::new(Repo::new(Arc::new(db_conn)));
let needs = Arc::new(Needs {
command_pg_repo: pg_repo,
});
let handler = Handler::new(needs);
let new_player_input = PlayerInput {
id: "abc".to_string(),
};
let player = handler.handle(&new_player_input).await?;
dbg!(player);
Ok(())
}
The error:
error: captured variable cannot escape `FnMut` closure body
--> src/main.rs:62:13
|
57 | let mut tx = self.pool.begin().await.unwrap();
| ------ variable defined here
...
61 | let shirt_next_value = Box::new(|model: String| {
| - inferred to be a `FnMut` closure
62 | self::Shirt::shirt_get_next_and_increase(self, &mut tx, model)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--^^^^^^^^
| | |
| | variable captured here
| returns a reference to a captured variable which escapes the closure body
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
error[E0597]: `tx` does not live long enough
--> src/main.rs:62:65
|
55 | lambda: &Lambda<'_, PlayerCreateLambdaArgs<'a>, DomainPlayer>,
| ------ lifetime `'1` appears in the type of `lambda`
...
61 | let shirt_next_value = Box::new(|model: String| {
| --------------- value captured here
62 | self::Shirt::shirt_get_next_and_increase(self, &mut tx, model)
| ^^ borrowed value does not live long enough
...
65 | let domain_player = lambda(PlayerCreateLambdaArgs { shirt_next_value }).await?;
| ---------------- this usage requires that `tx` is borrowed for `'1`
...
76 | }
| - `tx` dropped here while still borrowed
error[E0499]: cannot borrow `tx` as mutable more than once at a time
--> src/main.rs:71:34
|
55 | lambda: &Lambda<'_, PlayerCreateLambdaArgs<'a>, DomainPlayer>,
| ------ lifetime `'1` appears in the type of `lambda`
...
61 | let shirt_next_value = Box::new(|model: String| {
| --------------- first mutable borrow occurs here
62 | self::Shirt::shirt_get_next_and_increase(self, &mut tx, model)
| -- first borrow occurs due to use of `tx` in closure
...
65 | let domain_player = lambda(PlayerCreateLambdaArgs { shirt_next_value }).await?;
| ---------------- this usage requires that `tx` is borrowed for `'1`
...
71 | .fetch_one(&mut *tx)
| ^^ second mutable borrow occurs here
Some errors have detailed explanations: E0499, E0597.
For more information about an error, try `rustc --explain E0499`.
There are 3 main issues with the code (more like 2 and a half):
Closures cannot return references to things the closure owns, or things the closure borrowed mutably (More formally: the return type of the Fn* function/closure family of traits cannot borrow from the closure type itself). One way to fix this is to have tx be moved into the closure, and then moved into the closure's returned Future. Shared ownership can be achieved with std::sync::Arc, and cloning it and moving it when you need to give another task ownership.
Fn closures may be called concurrently, so they cannot use mutable references to things the closure owns or has borrowed, but this code tries to use a &mut tx borrowing from the outer scope inside a Fn closure. (This issue is bypassed with the solution outlined below).
If you want to access something mutably when it is shared, you need to synchronize those accesses so only one thing can actually access it at a time. One way to do this in async Rust is using tokio::sync::Mutex.
Combining the above, putting tx into a Arc<Mutex<...>>, moving .clone()s of the Arc into the tasks that need ownership, and .lock().awaiting whenever you need to access it mutably may fix your problem (it makes it compile at least).
Rust explorer
diff --git a/src/main.rs b/src/main.rs
index 89fc611..6f7d375 100644
--- a/src/main.rs
+++ b/src/main.rs
## -1,5 +1,7 ##
use std::{future::Future, pin::Pin, sync::Arc};
+use tokio::sync::Mutex;
+
pub trait Trait: Send + Sync + Player + Shirt {}
impl<T: Player + Shirt> Trait for T {}
## -42,12 +44,19 ## impl Player for Repo {
_input: &PlayerInput,
lambda: &Lambda<'_, PlayerCreateLambdaArgs<'a>, DomainPlayer>,
) -> Result<DomainPlayer, String> {
- let mut tx = self.pool.begin().await.unwrap();
+ let tx = Arc::new(Mutex::new(self.pool.begin().await.unwrap()));
// use _input here
- let shirt_next_value = Box::new(|model: String| {
- self::Shirt::shirt_get_next_and_increase(self, &mut tx, model)
+ let shirt_next_value = Box::new({
+ let tx = tx.clone();
+ move |model: String| -> Pin<Box<dyn Future<Output = Result<i64, std::string::String>> + Send>> {
+ let tx = tx.clone();
+ Box::pin(async move {
+ self::Shirt::shirt_get_next_and_increase(self, &mut *tx.lock().await, model)
+ .await
+ })
+ }
});
let domain_player = lambda(PlayerCreateLambdaArgs { shirt_next_value }).await?;
## -56,7 +65,7 ## impl Player for Repo {
sqlx::query_as::<_, DomainPlayer>("INSERT INTO player (...) VALUES (...) RETURNING *")
.bind(domain_player.id)
.bind(domain_player.shirt_number)
- .fetch_one(&mut *tx)
+ .fetch_one(&mut *tx.lock().await)
.await
.unwrap();
Note that because a &mut PgConenction is passed to shirt_get_next_and_increase inside the async block, which references the MutexGuard<Transaction<...>> returned by tx.lock().await, the MutexGuard will be held until shirt_get_next_and_increase completes, even while it yeilds (if it yields). This shouldn't be an issue in this code, since it appears to be mostly sequential, and does not access tx until shirt_get_next_and_increase has completed. If this is not what you want, (i.e. if your actual code does access tx concurrently while shirt_get_next_and_increase is running) you could instead have shirt_get_next_and_increase take a &Mutex<Transaction<...>>, and only have it hold the lock when it needs to access the connection.
An sketch of an alternate solution would be to restructure the code so that the Transaction is passed around by value in function arguments and return values, e.g.
pub type Lambda<'a, ArgT, ResT> =
dyn Fn(ArgT) -> Pin<Box<dyn Future<Output = Result<(ResT, ArgT), String>> + Send + 'a>> + Sync + 'a;
// ...
async fn shirt_get_next_and_increase<'a>(
&'a self,
mut tx: sqlx::Transaction<'static, sqlx::PgConnection>,
_model: String,
) -> Result<(i64, sqlx::Transaction<'static, sqlx::PgConnection>), String> {
// ...
Ok((value, tx))
}
This could resolve the borrowing and shared-mutability issues, but may make the API more cumbersome, and may be infeasible for other reasons.
I'm a new rustacean and I try to pass a function as argument in another function in order to create threads with the function pass as argument.
Here the code:
use std::os::unix::net::{UnixListener, UnixStream};
use std::thread;
use std::io::Read;
use anyhow::Context;
pub struct SocketServer {
path: String,
listener: UnixListener,
}
impl SocketServer {
pub fn new(path: &str) -> anyhow::Result<SocketServer>{
if std::fs::metadata(path).is_ok() {
println!("A socket is already present. Deleting...");
std::fs::remove_file(path).with_context(|| {
format!("could not delete previous socket at {:?}", path)
})?;
}
let socket_listener =
UnixListener::bind(path).context("Could not create the unix socket")?;
let path = path.to_string();
Ok(SocketServer{ path, listener: socket_listener })
}
pub fn start(&self, f: &dyn Fn(UnixStream)) -> anyhow::Result<()>{
for stream in self.listener.incoming() {
match stream {
Ok(stream) => {
thread::spawn(||f(stream));
}
Err(err) => {break;}
}
}
Ok(())
}
}
pub fn handle_stream(mut unix_stream: UnixStream) -> anyhow::Result<()> {
let mut message = String::new();
unix_stream
.read_to_string(&mut message)
.context("Failed at reading the unix stream")?;
println!("We received this message: {}", message);
Ok(())
}
Here the error I get when in try to compile:
error[E0277]: `dyn Fn(UnixStream)` cannot be shared between threads safely
--> src/socket.rs:34:35
|
34 | thread::spawn(||f(stream));
| ------------- ^^^^^^^^^^^ `dyn Fn(UnixStream)` cannot be shared between threads safely
| |
| required by a bound introduced by this call
|
= help: the trait `Sync` is not implemented for `dyn Fn(UnixStream)`
= note: required for `&dyn Fn(UnixStream)` to implement `Send`
I got some information in the Rust book but I still don't understand which function need to implement what.
Can you give me some hints? (Advice on other parts are welcome too)
I tried to remove closure but it goes to another error:
error[E0277]: expected a `FnOnce<()>` closure, found `()`
--> src/socket.rs:34:35
|
34 | thread::spawn(f(stream));
| ------------- ^^^^^^^^^ expected an `FnOnce<()>` closure, found `()`
| |
| required by a bound introduced by this call
|
= help: the trait `FnOnce<()>` is not implemented for `()`
= note: wrap the `()` in a closure with no arguments: `|| { /* code */ }`
note: required by a bound in `spawn`
--> /rust/lib/rustlib/src/rust/library/std/src/thread/mod.rs:661:8
|
661 | F: FnOnce() -> T,
| ^^^^^^^^^^^^^ required by this bound in `spawn`
Is there a reason you need a dyn Fn?
The easiest is probably to accept a impl Fn(UnixStream) + Send + Clone + 'static instead
pub fn start<F>(&self, f: F) -> anyhow::Result<()>
where
F: Fn(UnixStream) + Send + Clone + 'static,
{
for stream in self.listener.incoming() {
let f = f.clone();
match stream {
Ok(stream) => {
thread::spawn(move || f(stream));
}
Err(err) => break,
}
}
Ok(())
}
The dyn Fn() may capture things (such as Rcs) that are unsafe to share between threads. So you need to mark it Sync:
pub fn start(&self, f: &(dyn Fn(UnixStream) + Sync)) -> anyhow::Result<()> {
Now you'll get another error:
error[E0521]: borrowed data escapes outside of associated function
--> src/lib.rs:34:21
|
30 | pub fn start(&self, f: &(dyn Fn(UnixStream) + Sync)) -> anyhow::Result<()> {
| - - let's call the lifetime of this reference `'1`
| |
| `f` is a reference that is only valid in the associated function body
...
34 | thread::spawn(|| f(stream));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| `f` escapes the associated function body here
| argument requires that `'1` must outlive `'static`
Because the function's captured data may be dropped before the thread exits, causing use after free. The easiest solution is to use Arc:
pub fn start(&self, f: Arc<dyn Fn(UnixStream) + Sync + Send>) -> anyhow::Result<()> {
for stream in self.listener.incoming() {
match stream {
Ok(stream) => {
let f = Arc::clone(&f);
thread::spawn(move || f(stream));
}
Err(err) => {
break;
}
}
}
Ok(())
}
(You also need a Send bound).
I'm trying to move some data around b/w different threads but am getting the ole Copy trait-not-implemented error. Here's some code:
use std::future::Future;
use std::marker::PhantomData;
use std::sync::{Arc, Mutex};
/// Start external crates mocked here
#[derive(Clone, PartialEq, Eq)]
pub struct DecodeError {
inner: Box<Inner>,
}
#[derive(Clone, PartialEq, Eq)]
struct Inner {}
#[derive(Clone)]
pub struct Connection {}
pub trait Message: core::fmt::Debug + Send + Sync {
fn decode<B>(mut buf: B) -> Result<Self, DecodeError>
where
B: bytes::Buf,
Self: Default,
{
// do stuff
let mut message = Self::default();
Ok(message)
}
}
#[derive(Clone, Debug, Default)]
pub struct Request {}
impl Message for Request {}
#[derive(Clone, Debug, Default)]
pub struct Response {}
impl Message for Response {}
pub struct OtherResponse {}
pub enum ReplyError {
InvalidData,
}
pub struct EventMessage {
data: Vec<u8>,
}
pub struct Subscription {}
impl Subscription {
pub async fn next(&self) -> Option<EventMessage> {
Some(EventMessage { data: vec![] })
}
}
/// End external crates mocked here
#[derive(Clone)]
pub struct Publisher<T> {
connection: Connection,
subject: String,
resource_type: PhantomData<*const T>,
}
#[derive(Debug)]
pub enum PublishError {
SerializeError(String),
PublishError(String),
}
pub type PublishResult<T> = std::result::Result<T, PublishError>;
impl<T: Message> Publisher<T> {
pub fn new(connection: Connection, subject: String) -> Self {
let resource_type = PhantomData;
Publisher {
connection: connection,
subject,
resource_type,
}
}
pub async fn publish(&self, msg: T) -> PublishResult<()>
where
T: Message,
{
// do stuff to msg
Ok(())
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let node = Node::new("127.0.0.1", "node".into())
.await
.expect("connecting to NATS");
let p: Publisher<Request> = node.get_publisher("TOPIC".into());
let _submission_replyer: AsynkReplyer<Request, Response> = node
.get_replyer("request".into(), move |req: Arc<Mutex<Request>>| async {
let mut req = req.clone().lock().unwrap();
p.clone().publish(*req);
Ok(Response {})
})
.await;
Ok(())
}
pub struct Node {
name: String,
connection: Connection,
}
pub type ReplyResult<T> = std::result::Result<T, ReplyError>;
impl Node {
pub async fn new(_nats_url: &str, name: String) -> std::io::Result<Self> {
env_logger::init();
let connection = Connection {};
Ok(Node { name, connection })
}
pub fn get_publisher<T>(&self, subject: String) -> Publisher<T>
where
T: Message + Default,
{
Publisher::new(self.connection.clone(), subject)
}
pub async fn get_replyer<Req, Resp, Fut>(
&self,
subject: String,
callback: impl Fn(Arc<Mutex<Req>>) -> Fut + Send + Sync + 'static + Copy,
) -> AsynkReplyer<Req, Resp>
where
Req: Message + Default + 'static,
Resp: Message + Default,
Fut: Future<Output = ReplyResult<Resp>> + Send,
{
AsynkReplyer::new(&self.connection, subject, callback).await
}
}
pub struct AsynkReplyer<Req, Resp> {
request_type: PhantomData<Req>,
response_type: PhantomData<Resp>,
}
impl<Req: Message + Default + 'static, Resp: Message + Default> AsynkReplyer<Req, Resp> {
pub async fn new<Fut>(
connection: &Connection,
subject: String,
callback: impl Fn(Arc<Mutex<Req>>) -> Fut + Send + Sync + 'static + Copy,
) -> AsynkReplyer<Req, Resp>
where
Fut: Future<Output = ReplyResult<Resp>> + Send,
{
Self::start_subscription_handler(Subscription {}, callback).await;
AsynkReplyer {
request_type: PhantomData,
response_type: PhantomData,
}
}
pub async fn start_subscription_handler<Fut>(
subscription: Subscription,
callback: impl Fn(Arc<Mutex<Req>>) -> Fut + Send + Sync + 'static + Copy,
) where
Fut: Future<Output = ReplyResult<Resp>> + Send,
{
tokio::spawn(async move {
loop {
match subscription.next().await {
Some(msg) => {
Self::handle_request(msg, callback).await;
}
None => {
break;
}
}
}
});
}
/// Decodes + spins up another task to handle the request
pub async fn handle_request<Fut>(
msg: EventMessage,
callback: impl Fn(Arc<Mutex<Req>>) -> Fut + Send + Sync + 'static + Copy,
) -> ReplyResult<()>
where
Fut: Future<Output = ReplyResult<Resp>> + Send,
{
let decoded = Req::decode(msg.data.as_slice()).map_err(|_| ReplyError::InvalidData)?;
tokio::spawn(async move {
match callback(Arc::new(Mutex::new(decoded))).await {
Ok(response) => {
// do stuff
}
Err(e) => {}
}
});
Ok(())
}
}
error:
error[E0277]: the trait bound `Publisher<Request>: std::marker::Copy` is not satisfied in `[closure#src/main.rs:93:40: 97:10]`
--> src/main.rs:93:10
|
93 | .get_replyer("request".into(), move |req: Arc<Mutex<Request>>| async {
| __________^^^^^^^^^^^___________________-
| | |
| | within `[closure#src/main.rs:93:40: 97:10]`, the trait `std::marker::Copy` is not implemented for `Publisher<Request>`
94 | | let mut req = req.clone().lock().unwrap();
95 | | p.clone().publish(*req);
96 | | Ok(Response {})
97 | | })
| |_________- within this `[closure#src/main.rs:93:40: 97:10]`
|
= note: required because it appears within the type `[closure#src/main.rs:93:40: 97:10]`
error[E0277]: `*const Request` cannot be sent between threads safely
--> src/main.rs:93:10
|
93 | .get_replyer("request".into(), move |req: Arc<Mutex<Request>>| async {
| __________^^^^^^^^^^^___________________-
| | |
| | `*const Request` cannot be sent between threads safely
94 | | let mut req = req.clone().lock().unwrap();
95 | | p.clone().publish(*req);
96 | | Ok(Response {})
97 | | })
| |_________- within this `[closure#src/main.rs:93:40: 97:10]`
|
= help: within `[closure#src/main.rs:93:40: 97:10]`, the trait `Send` is not implemented for `*const Request`
= note: required because it appears within the type `PhantomData<*const Request>`
note: required because it appears within the type `Publisher<Request>`
--> src/main.rs:53:12
|
53 | pub struct Publisher<T> {
| ^^^^^^^^^
= note: required because it appears within the type `[closure#src/main.rs:93:40: 97:10]`
error[E0277]: `*const Request` cannot be shared between threads safely
--> src/main.rs:93:10
|
93 | .get_replyer("request".into(), move |req: Arc<Mutex<Request>>| async {
| __________^^^^^^^^^^^___________________-
| | |
| | `*const Request` cannot be shared between threads safely
94 | | let mut req = req.clone().lock().unwrap();
95 | | p.clone().publish(*req);
96 | | Ok(Response {})
97 | | })
| |_________- within this `[closure#src/main.rs:93:40: 97:10]`
|
= help: within `[closure#src/main.rs:93:40: 97:10]`, the trait `Sync` is not implemented for `*const Request`
= note: required because it appears within the type `PhantomData<*const Request>`
note: required because it appears within the type `Publisher<Request>`
--> src/main.rs:53:12
|
53 | pub struct Publisher<T> {
| ^^^^^^^^^
= note: required because it appears within the type `[closure#src/main.rs:93:40: 97:10]`
I can't (or can I) add the Copy attribute on the Publisher struct but that wont work since not all of its fields implement Copy. Despite this I've commented out the fields in Publisher that don't impl Copy and added the attribute to it just to see, and with that approach I get:
the trait `std::marker::Copy` is not implemented for `Request`
Request is a protobuf based struct compiled using the prost lib. I'm not able to add the Copy attribute to that because of some of its fields not implementing Copy such as String and Timestamp.
I'm wondering if the design here is just inherently bad or if there's a simple fix.
It seems to me, you've constrained that the Fn is Copy because you are passing it to multiple tokio::spawn calls. You've found that Copy is very restrictive, however Clone is not. You should use it instead and simply call .clone() when you handle the new request:
Self::handle_request(msg, callback.clone()).await;
Then the only errors are '*const Request' cannot be sent between threads safely. The compiler does not automatically implement Send or Sync for pointers because it doesn't know if that's safe, but your Fn needs to be called from different threads. Fortunately, you don't need to worry about that. Whether your PhantomData<*const T> is there simply to satisfy the compiler or to enforce specific variance, you can get the same result like this:
resource_type: PhantomData<fn() -> *const T>
Then, now that we've fixed the type constraint errors, the compiler now produces errors about lifetimes:
req.clone().lock().unwrap() doesn't work because the result of .lock() is tied to the value from req.clone(), but that gets dropped immediately. The fix is that the .clone() is unnecessary and can be removed.
p.clone().publish(*req) doesn't work since dereferencing a MutexLockGuard cannot provide a owned value, only a reference. You can fix this by adding a .clone() instead. If instead you think the Arc parameter is exclusive, you can get ownership by following the advice here: How to take ownership of T from Arc<Mutex<T>>?
The last lifetime error is a bit fuzzy because it has to do with the lifetime of the returned Future being tied to the req parameter. This can be fixed by using async move { } but then p is moved out of the closure into the future, meaning it is no longer Fn. What you want is to move req but move a clone of p. You can do this like so:
move |req: Arc<Mutex<Request>>| {
let p = p.clone();
async move {
// ...
}
}
"now I'm trying to resolve errs related to await-ing p.publish" - the error has to do with the lock now persisting across an await point, but since the mutex guard doesn't implement Send, the Future cannot be Send. You can fix this by locking and cloning in one step, so the lock isn't held:
let req = req.lock().unwrap().clone();
p.publish(req);
Ok(Response {})
See this compiling on the playground. There are still a number of warnings that should be addressed (unused Results), but I hope this gets you on the right path.
It is really very difficult to help you with this information. The full error code would probably be useful.
Anyway, in "impl Node ... get_replyer()" you see that's callback should return somehink that's implement Copy
pub async fn get_replyer<Req, Resp, Fut>(
&self,
subject: String,
callback: impl Fn(Arc<Mutex<Req>>) -> Fut + Send + Sync + 'static + Copy,
//-------------------------------------------------------------------^
) -> AsynkReplyer<Req, Resp>
In main
let _submission_replyer: AsynkReplyer<Resuest, Response> = node
.get_replyer(
"request".into(),
move |req: Arc<Mutex<Request>>| async {
let mut req = req.lock().unwrap();
p.publish(*req);
Ok(Response {
header: None,
response: Some(OtherResponse {
request: None,
status: 0,
}),
})
//-----------^------------------------------- Return a enum std::result::Result
},
)
.await;
std::result::Result implement Copy but wath about Response? The error is showed at this point?
In the example code below, a non-send value, Vec<T>, is moved into a function that returns something else. At this point, I no longer care about that vector. The returned object stores no reference to it, it no longer exists.
However, when I .await on the next line I get the error "captured value is not Send". Which it isn't, but since it should have been destroyed when vector_as_string exited, it doesn't need to send it across threads when the future restarts, because that variable is never used again.
use async_trait::async_trait;
async fn write_value(value: Vec<u8>) {
println!("something")
}
fn vector_as_string<T>(vec: Vec<T>) -> Vec<u8> {
Vec::new()
}
#[async_trait]
trait Writer {
async fn write_array<T>(&mut self, value: Vec<T>);
}
pub struct WriterImplementation {}
#[async_trait]
impl Writer for WriterImplementation {
async fn write_array<T>(&mut self, value: Vec<T>) {
let string = vector_as_string(value);
write_value(string).await
}
}
#[tokio::main]
async fn main() {
println!("Hi");
}
Dependencies:
[dependencies]
tokio = { version = "1.9.0", features = ["full"]}
async-trait = "0.1.51"
Error:
error: future cannot be sent between threads safely
--> src/main.rs:20:55
|
20 | async fn write_array<T>(&mut self, value: Vec<T>) {
| _______________________________________________________^
21 | | let string = vector_as_string(value);
22 | |
23 | | write_value(string).await
24 | | }
| |_____^ future created by async block is not `Send`
|
note: captured value is not `Send`
--> src/main.rs:20:40
|
20 | async fn write_array<T>(&mut self, value: Vec<T>) {
| ^^^^^ has type `Vec<T>` which is not `Send`
= note: required for the cast to the object type `dyn Future<Output = ()> + Send`
help: consider further restricting this bound
|
20 | async fn write_array<T + std::marker::Send>(&mut self, value: Vec<T>) {
| ^^^^^^^^^^^^^^^^^^^
Adding T: Send as it suggests allows it to compile, but why does T need to be Send if we aren't holding any T's across the await, as it has already been moved?
From the async_trait documentation:
Async fns get transformed into methods that return Pin<Box<dyn Future + Send + 'async>> and delegate to a private async freestanding function.
Not all async traits need futures that are dyn Future + Send. To avoid having Send and Sync bounds placed on the async trait methods, invoke the async trait macro as #[async_trait(?Send)] on both the trait and the impl blocks.
Applied to your case:
#[async_trait(?Send)]
trait Writer {
async fn write_array<T>(&mut self, value: Vec<T>);
}
#[async_trait(?Send)]
impl Writer for WriterImplementation {
async fn write_array<T>(&mut self, value: Vec<T>) {
let string = vector_as_string(value);
write_value(string).await
}
}
I have a struct with a member. The implementation returns an async stream which changes this member on a specific event (in the example on each).
This fails with a lifetime error, which is understandable, since the struct itself is not necessarily in the same lifetime as the map in the stream. it sounds similar to lifetime around async and stream, but I am not sure if it is related.
use async_std::pin::Pin;
use futures::{Stream, StreamExt};
use std::time::Duration;
struct StreamProvider {
value: u16,
}
impl StreamProvider {
fn returnastream(self: &mut Self) -> Pin<Box<dyn Stream<Item = i32>>> {
return async_std::stream::interval(Duration::from_millis(1000))
.map(|_| {
// change a value of Self within the stream
self.value = self.value + 1;
1
})
.boxed();
}
}
#[async_std::main]
async fn main() {
let mut object = StreamProvider { value: 1 };
let mut worx = object.returnastream();
// subscribing to the items
while let item = worx.next().await {
match item {
Some(value) => println!("{}", value),
_ => {}
}
}
}
[dependencies]
futures = "0.3.6"
async-std = { version = "1.6.5", features = ["attributes", "unstable"] }
The Error message:
/Users/andre/.cargo/bin/cargo run --color=always --package traittest --bin traittest
Compiling traittest v0.1.0 (/Users/andre/repos/traittest)
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/main.rs:20:12
|
20 | }).boxed();
| ^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 14:3...
--> src/main.rs:14:3
|
14 | / fn returnastream(self: &mut Self) -> Pin<Box<dyn Stream<Item=i32>>> {
15 | | return async_std::stream::interval(Duration::from_millis(1000))
16 | | .map(|_| {
17 | | // change a value of Self within the stream
... |
20 | | }).boxed();
21 | | }
| |___^
note: ...so that the type `futures_util::stream::stream::map::Map<async_std::stream::interval::Interval, [closure#src/main.rs:16:14: 20:10 self:&mut &mut StreamProvider]>` will meet its required lifetime bounds
--> src/main.rs:20:12
|
20 | }).boxed();
| ^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
--> src/main.rs:15:12
|
15 | return async_std::stream::interval(Duration::from_millis(1000))
| ____________^
16 | | .map(|_| {
17 | | // change a value of Self within the stream
18 | | self.value = self.value + 1;
19 | | 1
20 | | }).boxed();
| |__________________^
= note: expected `std::pin::Pin<std::boxed::Box<(dyn futures_core::stream::Stream<Item = i32> + 'static)>>`
found `std::pin::Pin<std::boxed::Box<dyn futures_core::stream::Stream<Item = i32>>>`
error: aborting due to previous error
Thanks to Peter Hall:
You need to use synchonisation primitives, for example Arc and Mutex, in order to access and mutate values that are owned by another thread.
This was the link I missed. Here's the result:
use std::time::Duration;
use async_std::pin::Pin;
use futures::{Stream, StreamExt};
use std::sync::{Arc, Mutex};
struct StreamProvider {
value: Arc<Mutex<u16>>,
}
impl StreamProvider {
fn returnastream(self: &mut Self) -> Pin<Box<dyn Stream<Item = i32>>> {
let v = self.value.clone();
return async_std::stream::interval(Duration::from_millis(1000))
.map(move |_| {
let mut a = v.lock().unwrap();
// change a value of Self within the stream
*a += 1;
1
})
.boxed();
}
}
#[async_std::main]
async fn main() {
let mut object = StreamProvider {
value: Arc::new(Mutex::new(1)),
};
let mut worx = object.returnastream();
// subscribing to the items
while let item = worx.next().await {
match item {
Some(_) => println!("{}", object.value.lock().unwrap()),
_ => {}
}
}
}
[dependencies]
futures = "0.3.6"
async-std = { version = "1.6.5", features = ["attributes", "unstable"] }