How can I test equality to a given boxed object implementing a trait?

Viewed 486

I'm writing a ray-tracer to learn Rust. I've got a Scene which contains Shapes, shapes that can intersect rays. Minimally, it is akin to:

pub trait Shape {
    fn draw(&self);
}

pub struct Plane {}

impl Shape for Plane {
    fn draw(&self) {}
}

pub struct Sphere {}

impl Shape for Sphere {
    fn draw(&self) {}
}

pub struct Scene {
    objects: Vec<Box<dyn Shape>>,
}

fn main() {
    let mut scene = Scene { objects: vec![] };

    let plane1 = Box::new(Plane {});
    let plane2 = Box::new(Plane {});
    let sphere = Box::new(Sphere {});

    scene.objects.push(plane1);
    scene.objects.push(plane2);
    scene.objects.push(sphere);

    for object in scene.objects {
        // I want to test if a given object in the scene is the same as another
        if object == plane2 {}
    }
}

Given a shape stored in Vec<Box<dyn Shape>> how can I test equality to a given boxed object implementing the Shape trait?

error[E0369]: binary operation `==` cannot be applied to type `std::boxed::Box<Shape>`
  --> src/main.rs:34:12
   |
34 |         if object == plane2 {}
   |            ^^^^^^^^^^^^^^^^
   |
   = note: an implementation of `std::cmp::PartialEq` might be missing for `std::boxed::Box<Shape>`

The test will be done in a Sphere or Plane member function, testing against self.

1 Answers

In C++, you can convert from a pointer to a Sphere to a pointer to an Intersector (ie. from a Sphere* to an Intersector*). It also works with references although this is less idiomatic for C++.

This is exactly the same in Rust, except that in Rust it is more idiomatic to use references rather than raw pointers:

impl Scene {
    pub fn some_function(&self, intersector: &Intersector) {
        for object in &self.objects {
            if intersector == object {}
        }
    }
}

Note that your original code used *const Box<dyn Intersector> which is a pointer to a box containing an Intersector and translates roughly to smart_pointer<Intersector>* in C++, so your Rust code would be equivalent to passing an Intersector* to a function expecting a smart_pointer<Intersector>*, which doesn't work in C++ either.

Related