0

In a Rust application, I have a struct that does roughly the following:

struct Client {
  token: Option<String>,
}

impl Client {
  pub async fn login(&mut self) {
    // ...
    self.token = Some(token);
  }
}

In a different struct, which is intended to represent the lifetime of an application "session" (e.g. users cannot interact without an instance of this struct in memory), I use this Client:

struct App {
  client: Client,
}

impl App {
  pub fn new() -> Self {
    Self {
      client: Client { token: None }
    }
  }
}

So far so good.

I recently introduced a separate struct that I would like to share the client with, who also should be owned by App. Something like the following (which omits lifetimes and uses Option to avoid a local reference):

struct Store {
  client: Option<&Client>,
}
struct App {
  client: Client,
  store: Store,
}

impl App {
  pub fn new() -> Self {
    let client = Client { token: None }
    Self {
      client,
      store: Store { client: &client }
    };
  }
}

I believe this last block has issues with local references, but setting that aside, is this pattern possible? Or do all shared references need to be immutable?

Is there a Rust-friendly way to share a client that may become authenticated by an unrelated call like this?

Jesse
  • 10,370
  • 10
  • 62
  • 81
  • 1
    "Share...mutable..." is going to be a no-can-do. It's either mutable *or* shared. – tadman Jul 14 '23 at 01:44
  • While the marked duplicate answers part of this question, I am attempting to figure out what the right pattern is here - both the mutable reference part and the ownership part make sense to me, but as this feels like a common pattern in other languages, I was wondering what the Rust equivalent is. For now, I've solved this via dependency injection and lifting the shared token to the container and passing it into a stateless client. It's verbose. – Jesse Jul 14 '23 at 18:18
  • The right answer is _don't do it_. If you really, like, must, then there are solutions and they are also specified in the duplicate (`Rc` and `Weak`, self-referential crates), but avoid it as long as you can. – Chayim Friedman Jul 15 '23 at 18:59
  • Sorry for the unclear question. I'm looking for the right answer to "what is the Rust-y pattern here" (DI? Rc? Store primitives and allocate structs on the fly?), not "how do I share references". – Jesse Jul 20 '23 at 16:13
  • 1
    It is hard to answer what the Rusty solution will be, because you described the problem with a very broad outline. All I can say is "don't have a struct (`App`) that have a struct (`Store`) that stores a reference to a struct (`Client`) owned by the same struct (`App`)". You can, for example, use `Store` not-owned-by-`App`, or provide the `&Client` for `Store` at each method call. – Chayim Friedman Jul 20 '23 at 16:34

0 Answers0