#mutable variable in async function

10 messages · Page 1 of 1 (latest)

vivid sonnet
#

I tried making this piece of code below work. It gets close to the real implementation, but it is slightly different.

pub async fn do_some_client_stuff<'a>(cfg: &'a Config) {

  // setup mutable client
  let mut client = Client::new(cfg.addr, ...);

  // try to connect
  if let Err(err) = client.connect().await {
    //                     ^^^^^^^ signature: pub async fn connect(&mut self) -> Result<(), Error> 
    return Self::panic(Reason::new(format!("Could not client 1: {}", err).as_str()))
  }

  // do some other stuff with the client (reusage of the cient)
  // ...

The problem I have comes down to this error:

required for the cast from `Pin<Box<[async block@###.rs:69:1: 73:3]>>` to `Pin<Box<(dyn Future<Output = ###> + Send + 'async_trait)>>```

I know one of the types inside the config does not have the copy trait and thus I cannot use the pass by value. So I want to pass a `&mut Client` that takes ownership and returns ownership eventually after it is completed so I can put the value in another struct. Am I missing something?
covert wolf
#

&mut T doesn't take ownership, and also can't take ownership so it's not possible to have a &mut T that takes ownership and returns ownership

What you'd do in that case is pass by value, and then return by value

The types inside not being Copy just means you can't copy it, but you can still transfer ownership

If you want multiple owners then you'd want to use the Rc/Arc reference counted pointer types

vivid sonnet
#

I cannot return the value, because the connect function uses it and is part of an external crate

covert wolf
#

Oh but the problem isn't to do with ownership right?, judging from the error you posted it seems it's expecting the Client to be Send in order to call connect on it

Is Client a type under your control?, you would need to make sure Client is Send if trying to use it in a context that requires Send

If it's part of an external crate then it's possible it's not intended to be used in a Send context

vivid sonnet
#

The client is under my control, but the inner type that handles the connection is not within my control

#
pub struct Client {
    server_address: SocketAddr,
    pub connected: Option<ConnectedSocket>,
    ...
}
covert wolf
vivid sonnet
#

The problem with this is the fact that it is not thread safe...

covert wolf
#

Yeah, if it's not thread safe though then there will either be a good reason for it not being sendable, or an oversight

Seems like the ConnectedSocket type is the one that's !Send right?

I'd check the documentation for the crate to see if it mentions why it's not safe to send to another thread

IFF it's actually safe to send this across thread boundaries and the fact it's !Send is an oversight (ConnectedSocket uses a !Send type but could actually be Send - they just haven't unsafely implemented it) - then you can unsafely implement Send for your Client

unsafe impl Send for Client {}
#

But definitely sending an actually non-thread-safe value to another thread would be bad news.... If there's a good reason for it to not be sent you should not try to