Constructor which takes a Struct or Arc implementing a trait

I have a struct which holds an Arc of a dynamic trait object.
For convenience, I want to have a constructor which either takes a struct and turns that into an Arc or directly takes an Arc. However, I haven't found a way which satisfies the compiler.

Minimal example:

use std::sync::Arc;

trait Shape { }

struct Sphere;

impl Shape for Sphere { }

struct Mesh {
    shape: Arc<dyn Shape>,
}

impl Mesh {
    fn new(shape: impl Into<Arc<dyn Shape>>) -> Self {
        Mesh { shape: shape.into() }
    }
}

fn main() {
    let _ = Mesh::new(Sphere);
    let _ = Mesh::new(Arc::new(Sphere));
}

You'll want to make new take in anything that implements Shape, then internally wrap that in an Arc. You can do this by either using impl Shape as type, or with a generic type T with a bound T: Shape. You'll also need to include a 'static bound, since a Arc<dyn Shape> implies that the contained type is 'static.

use std::sync::Arc;

trait Shape { }

struct Sphere;

impl Shape for Sphere { }

struct Mesh {
    shape: Arc<dyn Shape>,
}

impl Mesh {
    fn new(shape: impl Shape + 'static) -> Self {
        Mesh { shape: Arc::new(shape) }
    }
    
    fn new_v2<T: Shape + 'static>(shape: T) -> Self {
        Mesh { shape: Arc::new(shape) }
    }
}

fn main() {
    let _ = Mesh::new(Sphere);
    let _ = Mesh::new_v2(Sphere);
}

If you want to support impl Shape, Arc<impl Shape>, and perhaps also Arc<dyn Shape> arguments, you can create your own trait

trait IntoArcDynShape {
    fn into_arc_dyn_shape(self) -> Arc<dyn Shape>;
}
impl<T: Shape + 'static> IntoArcDynShape for T {
    fn into_arc_dyn_shape(self) -> Arc<dyn Shape> {
        Arc::new(self)
    }
}
impl<T: Shape + 'static> IntoArcDynShape for Arc<T> {
    fn into_arc_dyn_shape(self) -> Arc<dyn Shape> {
        self
    }
}
impl IntoArcDynShape for Arc<dyn Shape> {
    fn into_arc_dyn_shape(self) -> Arc<dyn Shape> {
        self
    }
}

Rust Playground

Note however that this does prevent you from implementing Shape for Arc<…> itself.

What about just implementing From?

1 Like

This does, however, not work when I already have an Arc and want to supply it to the constructor.

(Updated the example to include that case)

Thanks, but in my actual code, the struct holds two Arcs, so I would need to implement all combinations manually, which I'd rather not do.

Thanks, that's exactly what I'm looking for. I'm not a huge fan of creating an extra trait for it, but I guess I'll have to work with it.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.