Corebreaker
Corebreaker

Reputation: 357

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

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).

Upvotes: 5

Views: 1245

Answers (2)

Corebreaker
Corebreaker

Reputation: 357

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

Upvotes: 0

Mike Graham
Mike Graham

Reputation: 76793

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)))
}

Upvotes: 1

Related Questions