Get Rc<RefCell<dyn T>>> on a sub-type

1.1k views Asked by At

I have the following definitions:

trait A {
    fn f(&self);
}

trait B: A {
// ...
}

I'd like implement this kind of function:

fn convert(v: Rc<RefCell<dyn B>>) -> Rc<RefCell<dyn A>> {
}

I'd like to have a way for returning a value that share the same object, that's means that with these declarations:

let x: Rc<RefCell<dyn B>> /* = ... */;
let y = convert(Rc::clone(&x));

The calls x.f() and y.f() apply the call on the same object.

How can i implement the function convert or how can change the type definitions to have that behaviour and that kind of conversion (a conversion to a sub-object).

2

There are 2 answers

4
Corebreaker On BEST ANSWER

Thank for your ideas, i decided to use a compromise by avoiding the use of a trait-object as parameter of the function convert in according to Rust rules:

use std::rc::Rc;
use std::cell::RefCell;

trait A {
    fn print(&self);
}

trait B: A {
}

trait Convert {
    fn convert(it: Rc<RefCell<Self>>) -> Rc<RefCell<dyn A>>;
}

struct MyType(u32);

impl Convert for MyType {
    fn convert(it: Rc<RefCell<Self>>) -> Rc<RefCell<dyn A>> {it}
}

impl A for MyType {
    fn print(&self) {
        println!("MyType({}) as A", self.0);
    }
}

impl B for MyType {}

fn main() {
    let a: Rc<RefCell<dyn A>>;
    {
        let b = Rc::new(RefCell::new(MyType(3)));
        a = Convert::convert(b.clone());
    }

    a.borrow().print();
}

Playground

2
Mike Graham On

Rust does not support direct upcasting of trait objects. Due to the way trait objects are implemented, this is not possible without extra work at runtime, so Rust makes you do the work yourself.

You can do it like e.g.

use std::rc::Rc;
use std::cell::RefCell;

trait A {
  fn f(&self) -> i32;
}

trait B: A {
}

struct Wrapper(Rc<RefCell<dyn B>>);

impl A for Wrapper {
    fn f(&self) -> i32 {
        A::f(&*self.0.borrow())
    }
}

fn convert(v: Rc<RefCell<dyn B>>) -> Rc<RefCell<dyn A>> {
    Rc::new(RefCell::new(Wrapper(v)))
}