asynchronousrustrust-tokiorwlock

How do I cast Arc<RwLock<dyn Child>> to Arc<RwLock<dyn Base>>


I currently have some code like the following:

use std::sync::{Arc, RwLock};

// Define traits
trait Child: Base {
    fn method_a(&self);
}

trait Base {
    fn method_b(&self);
}

// Struct implementing both traits
struct MyStruct {
    something: i32,
};

impl Child for MyStruct {
    fn method_a(&self) {
        println!("Method A");
    }
}

impl Base for MyStruct {
    fn method_b(&self) {
        println!("Method B");
    }
}

fn do_some_processing(parent: &Arc<RwLock<dyn Child>>) -> Arc<RwLock<dyn Base>> {
    //How do i do this?
}

fn main() {
    let my_struct = Arc::new(RwLock::new(MyStruct));

    let base = do_some_processing(&my_struct);

}

I want to limit the functions used after do_some_processing has been called. That is the reason for the two traits.


Solution

  • Upcasting coercion is not yet stable. So this could work in +nightly

    #![feature(trait_upcasting)]
    use std::sync::{Arc, RwLock};
    
    // Define traits
    trait Child: Base {
        fn method_a(&self);
    }
    
    trait Base {
        fn method_b(&self);
    }
    
    // Struct implementing both traits
    struct MyStruct {
        something: i32,
    }
    
    impl Child for MyStruct {
        fn method_a(&self) {
            println!("Method A");
        }
    }
    
    impl Base for MyStruct {
        fn method_b(&self) {
            println!("Method B");
        }
    }
    
    fn do_some_processing(parent: &Arc<RwLock<dyn Child>>) -> Arc<RwLock<dyn Base>> {
        parent.clone()
    }
    
    
    
    fn main() {
        let my_struct: Arc<RwLock<dyn Child>> = Arc::new(RwLock::new(MyStruct { something: 42 }));
    
        let base = do_some_processing(&my_struct);
    
    }
    

    ---OR---

    If you want to stick to stable you will need some wrapper

    use std::sync::{Arc, RwLock};
    
    // Define traits
    trait Child: Base {
        fn method_a(&self);
    }
    
    trait Base {
        fn method_b(&self);
    }
    
    // Struct implementing both traits
    struct MyStruct {
        something: i32,
    }
    
    impl Child for MyStruct {
        fn method_a(&self) {
            println!("Method A");
        }
    }
    
    impl Base for MyStruct {
        fn method_b(&self) {
            println!("Method B");
        }
    }
    
    // Wrapper struct to manually upcast Child to Base
    struct BaseWrapper {
        inner: Arc<RwLock<dyn Child>>,
    }
    
    impl Base for BaseWrapper {
        fn method_b(&self) {
            self.inner.read().unwrap().method_b();
        }
    }
    
    fn upcast(child: Arc<RwLock<dyn Child>>) -> Arc<RwLock<dyn Base>> {
        Arc::new(RwLock::new(BaseWrapper { inner: child }))
    }
    
    fn main() {
        let my_struct: Arc<RwLock<dyn Child>> = Arc::new(RwLock::new(MyStruct { something: 42 }));
    
        let base = upcast(my_struct);
    
        base.read().unwrap().method_b();
    }