Trait object with access to containing Rc

Hello everyone. I have run into this problem a couple of times and was wondering if there is a nice pattern to solve it. I have a trait Trait which I want to use only in an Rc. I also want the implementations of the trait to be able to refer to their enclosing Rc.

trait Trait {
  fn thing(&self) -> Rc<Trait>;
}

struct TraitString(String);

impl Trait for TraitString {
  fn thing(&self) -> Rc<Trait> {
    // Return copy of enclosing Rc.
  }
}

Obviously this example has a bunch of problems as it doesn't enforce that you are calling it on an Rc and the impl doesn't even know about the Rc. However I can't find a way to write it. I have come up with the following (unsatisfactory) solutions.

Use an enum and have all possible implementations inline.

This allows me to impl on Rc<Thing> and then I can simply clone self to implement the method. However this requires me to centralize the implements and every method becomes an unsightly match.

impl Thing for Rc

This allows me to access and clone the Rc but now I need to wrap my thing in another layer of indirection because Rust doesn't know that all impls will be for Rc. This means that Rc<Thing> turns into Box<Rc<Thing>>

Make an impl trait with extra arguments

trait ThingImpl {
  fn thing(&self, rc_self: Rc<Thing>) -> Rc<Thing>;
}

struct Thing(Rc<ThingImpl>);

impl Thing {
 fn thing(&self) -> Rc<Thing> {
    self.0.thing(self.clone())
  }
}

This works but 1) requires this ugly wrapper. 2) Looses type-safety on the rc_self param. (You can do an unsafe cast because it will be the right type but that is ugly). This seems like the best solution however it requires a lot of unsafe and boilerplate code.

C++ has std::enable_shared_from_this which solves this problem but I was wondering if there is a nice solution in Rust.

It’s being worked on I believe: Tracking issue for `arbitrary_self_types` · Issue #44874 · rust-lang/rust · GitHub

2 Likes