Converting Rc<Trait> types


pub trait FrpNode<Out>: FrpNodeAny {
    fn get(&self) -> (u32, Ref<Out>);
}

pub trait FrpNodeAny {
    fn update(&self);
    fn parents(&self) -> Vec<Rc<dyn FrpNodeAny>>;
}

pub fn magic<Out>(x: Rc<dyn FrpNode<Out>>) -> Rc<dyn FrpNodeAny> {
  // need help writing this function
  // preferably without allocating a new Rc
}

Please note that above we have:

pub trait FrpNode<Out>: FrpNodeAny 

Is it possible to implement function 'magic'? It seems that if we a have a Rc to a "more detailed" trait, we should be able to get a Rc to the "less detailed" trait. Thanks!

Not automatically, you will need to implement methods on traits like this,

pub trait FrpNodeAny {
    fn update(&self);
    fn parents(&self) -> Vec<Rc<dyn FrpNodeAny>>;

    fn into_rc_any(self: Rc<Self>) -> Rc<FrpNodeAny>;
}

But this is burdensome on the user, the solution to this problem is yet another trait

pub trait IntoFrpNodeAny {
    fn into_rc_any(self: Rc<Self>) -> Rc<FrpNodeAny>;

    fn as_any(&self) -> &FrpNodeAny;
    fn as_any_mut(&mut self) -> &mut FrpNodeAny;

    // add methods for whatever pointer like type here
}

pub trait FrpNodeAny: IntoFrpNodeAny {
    fn update(&self);
    fn parents(&self) -> Vec<Rc<dyn FrpNodeAny>>;
}

// this is important, you can't move this implementation into the trait
// as default methods, because these coercions require `Sized` bounds
// which are provided here, but can't in the trait
impl<T: FrpNodeAny> IntoFrpNodeAny for T {
    fn into_rc_any(self: Rc<Self>) -> Rc<FrpNodeAny> { self }

    fn as_any(&self) -> &FrpNodeAny { self }
    fn as_any_mut(&mut self) -> &mut FrpNodeAny { self }
}

This way implementors of FrpNodeAny don't need to think about it, they just get it for free.

you can then use this like so,

pub fn magic<Out>(x: Rc<dyn FrpNode<Out>>) -> Rc<dyn FrpNodeAny> {
    x.into_rc_any()
}
3 Likes

There's something I'm missing. This is what I have so far:

use super::*;
use std::cell::Ref;

pub trait FrpNode<Out>: FrpNodeAny {
    fn get(&self) -> (u32, Ref<Out>);
}

pub trait FrpNodeAny {
    fn update(&self);
    fn parents(&self) -> Vec<Rc<dyn FrpNodeAny>>;
}

pub trait IntoFrpNodeAny {
    fn into_rc_any(self: Rc<Self>) -> Rc<FrpNodeAny>;
}

impl<T: FrpNodeAny + 'static> IntoFrpNodeAny for T {
    fn into_rc_any(self: Rc<Self>) -> Rc<FrpNodeAny> {
        self
    }
}

pub struct FrpBeh1<T0, Out> {
    n0: Rc<dyn FrpNode<T0>>,
    f: Rc<dyn Fn(&T0) -> Out>,
}

impl<T0, Out> FrpNodeAny for FrpBeh1<T0, Out> {
    fn update(&self) {
        unimplemented!()
    }

    fn parents(&self) -> Vec<Rc<FrpNodeAny>> {
        vec![self.n0.into_rc_any()]
    }
}

compile error:

   |
34 |         vec![self.n0.into_rc_any()]
   |                      ^^^^^^^^^^^ method not found in `std::rc::Rc<(dyn frp_node::FrpNode<T0> + 'static)>`
   |
   = note: the method `into_rc_any` exists but the following trait bounds were not satisfied:
           `dyn frp_node::FrpNode<T0> : frp_node::IntoFrpNodeAny`
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `into_rc_any`, perhaps you need to implement it:
           candidate #1: `frp_node::IntoFrpNodeAny`
pub trait FrpNodeAny: IntoFrpNodeAny {

You need this, sorry for the typo

1 Like

Everything works now. Thanks!

1 Like