How to convert a dyn trait within Arc into an Actix-web Data

Hello guys,

I have this traits and structs

pub trait Foo {}
pub struct MyFoo {}
impl Foo for MyFoo {}

trait Bar<T> where T: Foo {
    fn do_something(&self, my_foo: T) -> Result<T, str>;
}

pub struct MyBar {}
impl Bar<MyFoo> for MyBar {
    fn do_something(&self, my_foo: MyFoo) -> Result<(), str> {
        // MyBar implementation
        Ok(())
    }
}

pub struct YourBar {}
impl Bar<MyFoo> for YourBar {
    fn do_something(&self, my_foo: MyFoo) -> Result<(), str> {
        // YourBar implementation
        Ok(())
    }
}

fn test() {
    let arc_foo : Arc<dyn Bar<MyFoo> + Send + Sync> = wrapper.get_bar();
    let actix_data = Data::new(arc_foo.clone());
    // pass actix_data to the function expecting it
    // then call actix_data.do_something() that should execute the implementation of the current Bar (MyBar or YourBar)
}

I would like to extract the Bar variable to assemble an Actix-web Application state of type web::Data<T> where T: Bar<MyFoo>, something like
Data::new(arc_foo.clone())

I'm trying several solution but I'm not able to pass from one to another. I know that the Arc does contain a type that also implement Send and Sync, but I need them for other reasons. Is there a way to convert the first variable to the second one?

I think you might be referring to downcasting.

As for using it as Actix-web state, I think you will need to add a 'static bound besides Send and Sync.

(I interpreted the question more literally than downcasting, which could be the wrong interpretation.)

Is Bar your trait? If so, you can

impl<T: ?Sized + Bar<U>, U: Foo> Bar<U> for Arc<T> {}

If not, but MyFoo is yours, you could still

impl<T: ?Sized + Bar<MyFoo>> Bar<MyFoo> for Arc<T> {}
1 Like

Thanks quinedot,
however I've simplified my real code to ease it. With your solution I need to implement all the functions declared by the Bar trait but I would like to avoid this approach because my real implementations are within MyBar and YourBar and I would use those ones.
Or is there a way to bind them?

It is true that implementing traits for containers can be a lot of boilerplate. Sometimes macros or clever bounds on blanket implementations can help.

Beyond that, I don't understand what exactly you mean. Perhaps provide an example of what you have and what you're trying to avoid.[1]


  1. Side note, going AFK for awhile; any reply won't be immediate. ↩ī¸Ž

I'm sure to follow you, can you give me some more info or some useful link please?

I've extended the code of the question, is it clearer now or should I add more info?

Your implementations don't match the trait declaration (and str is not Sized). But this maybe? the only real relevant addition is calling the dyn Bar<U> from &Arc<dyn ...>.

impl<T: Bar<U> + ?Sized, U: Foo> Bar<U> for Arc<T> {
    fn do_something(&self, my_foo: U) -> Result<U, String> {
        (**self).do_something(my_foo)
    }
}
1 Like

This solution is working, even if I had to tweak a bit to adhere to my real implementation where I have aysnc traits so some Send + Sync were required to make it working. Moreover, as suggested by @moy2010 I had to add the static bound besides Send and Sync to be able to pass to the actix Data.
So for the others, starting with:

#[async_trait]
trait Bar<T> where T: Foo {
    async fn do_something(&self, my_foo: T) -> Result<T, str>;
}

I ended up with

#[async_trait]
impl<T: ?Sized + Bar<U> + Sync + Send, U: Foo + Send + 'static> Bar<U> for Arc<T> {
    fn do_something(&self, my_foo: U) -> Result<U, String> {
        (**self).do_something(my_foo).await
    }
}

and the conversion to Data is:

let arc_bar : Arc<dyn Bar<MyFoo> + Send + Sync> = wrapper.get_bar();
let actix_data = Data::new(arc_bar.clone());