I've been writing a ray tracer in Rust and I've come across a problem. I have defined the following struct:
pub struct HitRecord{
mat : Rc<RefCell<dyn Material>,
...
}
The Material
trait has only one associated function:
pub trait Material{
fn scatter(&mut self,r_in : &mut Ray, rec : &HitRecord, attenuation : &mut Color, scattered : &mut Ray) -> bool;
}
That some structs (e.g. Lambertian
and Metal
) implement. I don't understand how I'm supposed to call this function from another piece of code:
let mut rec : HitRecord = HitRecord::new();
if world.hit(r, &mut Interval{min : 0.001, max : INFINITY} , &mut rec){
let mut scattered = Ray::new();
let mut attenuation = Color::new();
let temp = rec.mat.clone();
if temp.scatter(r, &rec, &mut attenuation,&mut scattered) {
return attenuation * self.ray_color(&mut scattered,depth-1,world);
}
return Color::new();
}
The function call world.hit()
requires rec
to be mutable, since it assigns to it. The problem occurs in the second if statement:
error[E0596]: cannot borrow data in an `Rc` as mutable
--> camera.rs:128:16
|
| if temp.get_mut().scatter(r, &rec, &mut attenuation,&mut scattered) {
| ^^^^^^^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<RefCell<dyn material::Material>>`
I tried implementing DerefMut
for dyn Material
but I got different errors regarding Deref
not being satisfied and upon implementing that various other errors; I wasn't able to implement it properly. I've also tried switching Rc<RefCell>
with other things, such as Rc
, Box
, Rc<Box>
to name a few, with fruitless results. I've searched for questions with similar error messages but I can't see how they apply to my case, if they do at all.
EDIT: A minimal example of the problem is as follows:
use std::cell::RefCell;
use std::rc::Rc;
use std::borrow::BorrowMut;
struct Stone;
trait Material {
fn scatter(&mut self, rec : &HitRecord){
println!("scattering");
}
}
impl Material for Stone {}
pub struct HitRecord{
pub mat : Rc<RefCell<dyn Material>>
}
impl HitRecord{
pub fn new() -> Self{
Self{
mat : Rc::new(RefCell::new(Stone)) as Rc<RefCell<dyn Material>>
}
}
}
fn main() {
let mut f = HitRecord::new();
// None of these compile
f.borrow_mut().scatter(&f.mat);
f.mat.borrow_mut().scatter(&f.mat);
f.mat.scatter(&f.mat);
}
The problem is you're importing BorrowMut
which also provides a different borrow_mut
method, but you want to call Rc::borrow_mut
so remove use std::borrow::BorrowMut
and write the following:
fn main() {
let f = HitRecord::new();
f.mat.borrow_mut().scatter(&f);
}
Note though, that you cannot access rec.mat
from inside that specific scatter
call in any meaningful way because it's already borrowed exclusively so any attempt to borrow it again will panic.
It is extremely rare that you need to import BorrowMut
especially in combination with Rc
and RefCell
you can usually just use the corresponding syntax: a.borrow_mut()
→ &mut a