Ludvig
Ludvig

Reputation: 637

Problem generating raytracing world due to lifetime errors

I'm stuck with how I should best make a world in Rust (it's for a raytracer). I've tried to make a small example here.

See playground here. I get lots of different lifetimes errors so maybe it's easier for you to just look at the code.

trait Material {}

struct Metal {}

impl Material for Metal {}

trait Hit {
    fn hit(&self) -> Option<HitRecord>;
}
struct Sphere<'a> {
    material: &'a dyn Material,
}

impl<'a> Hit for Sphere<'a> {
    fn hit(&self) -> Option<HitRecord> {
        Some(HitRecord {
            material: self.material,
        })
    }
}

struct HitRecord<'a> {
    material: &'a dyn Material,
}

#[derive(Default)]
struct World {
    materials: Vec<Box<dyn Material>>,
    hitables: Vec<Box<dyn Hit>>,
}

impl World {
    fn add_material(&mut self, mat: impl Material + 'static) -> &dyn Material {
        self.materials.push(Box::new(mat));
        self.materials.last().unwrap().as_ref()
    }
    
    fn add_hitable(&mut self, hitable: impl Hit + 'static) {
        self.hitables.push(Box::new(hitable));
    }
}

fn make_world() -> World {
    let mut world = World::default();
    let metal = Metal {};
    let metal = world.add_material(metal);
    let sphere = Sphere { material: metal };
    world.add_hitable(sphere);
    world
}

fn main() {
    let world = make_world();
}

Upvotes: 0

Views: 46

Answers (1)

NovaDenizen
NovaDenizen

Reputation: 5325

Rc is slightly less efficient than bare references, but they are a lot easier to work with.

use std::rc::Rc;

trait Material {}

struct Metal {}

impl Material for Metal {}

trait Hit {
    fn hit(&self) -> Option<HitRecord>;
}

struct Sphere {
    material: Rc<dyn Material>,
}

impl Hit for Sphere {
    fn hit(&self) -> Option<HitRecord> {
        Some(HitRecord {
            material: Rc::clone(&self.material),
        })
    }
}

struct HitRecord {
    material: Rc<dyn Material>,
}

#[derive(Default)]
struct World {
    materials: Vec<Rc<dyn Material>>,
    hitables: Vec<Rc<dyn Hit>>,
}

impl World {
    fn add_material(&mut self, mat: impl Material + 'static) -> Rc<dyn Material> {
        let rc: Rc<dyn Material> = Rc::new(mat);
        self.materials.push(Rc::clone(&rc));
        rc
    }
    fn add_hitable(&mut self, hitable: impl Hit + 'static) {
        self.hitables.push(Rc::new(hitable));
    }
}

fn make_world() -> World {
    let mut world = World::default();
    let metal = Metal {};
    let metal = world.add_material(metal);
    let sphere = Sphere { material: metal };
    world.add_hitable(sphere);
    world
}

fn main() {
    let world = make_world();
}

Playground link

Upvotes: 1

Related Questions