0

So I am trying to make my own octree in Rust, but I'm having trouble with my set function. It's supposed to be recursive, and there is a point where I am matching the child node. Except, it has two errors:

  1. It can't borrow a child as mutable, because it's behind a & reference.
  2. I don't know how to create a new child if it does exist. Since my Octree holds references to child Octrees, if I try to set the reference to a new one, it will drop the value.

I am kinda at a loss. Do I need to create a trait and then create types for the root, branches, and leaves? Or is there a way to save my code?

Code that breaks:

match self.children[index] { // Here it says I can't borrow it
            Some(ref mut child) => {
                child.set(pos, val);
            },
            None => {
                let mut new_pos = self.pos.clone();
                let new_size = self.size.clone() as i32/2 ;

                match index {
                    0 => { new_pos[0] -= new_size.clone(); new_pos[0] -= new_size.clone(); new_pos[0] -= new_size.clone(); },
                    1 => { new_pos[0] -= new_size.clone(); new_pos[0] -= new_size.clone(); new_pos[0] += new_size.clone(); },
                    2 => { new_pos[0] -= new_size.clone(); new_pos[0] += new_size.clone(); new_pos[0] -= new_size.clone(); },
                    3 => { new_pos[0] -= new_size.clone(); new_pos[0] += new_size.clone(); new_pos[0] += new_size.clone(); },
                    4 => { new_pos[0] += new_size.clone(); new_pos[0] -= new_size.clone(); new_pos[0] -= new_size.clone(); },
                    5 => { new_pos[0] += new_size.clone(); new_pos[0] -= new_size.clone(); new_pos[0] += new_size.clone(); },
                    6 => { new_pos[0] += new_size.clone(); new_pos[0] += new_size.clone(); new_pos[0] -= new_size.clone(); },
                    7 => { new_pos[0] += new_size.clone(); new_pos[0] += new_size.clone(); new_pos[0] += new_size.clone(); }
                    _ => { panic!("Index out of bounds"); }
                }

                let mut new_tree = Octree::new(new_size.clone() as u8, new_pos);
                new_tree.set(pos, val);
                *self.children[index] = Some(new_tree); // Here it says I can't write to it
            }
        }

Link to octree.rs Gist

1 Answers1

2

References are also known as borrows; their main purpose is to get temporary, “borrowed” access to a value that is owned by something else.

When you are defining a data structure, it should almost never contain references; instead, should use owned types. Sometimes this means writing T instead of &'a T; in this case, since the structure is recursive, it needs a pointer, but an owning one rather than a borrowing one — i.e. Box.

Change your structure definition from

pub struct Octree<'a, T> {
    children: [&'a Option<Octree<'a, T>>; 8],
    data: Option<T>,
    size: u8,
    pos: VecI3
}

to

pub struct Octree<T> {
    children: [Option<Box<Octree<T>>>; 8],
    data: Option<T>,
    size: u8,
    pos: VecI3
}

Notice that the structure no longer has a lifetime parameter — just as, for example, BTreeMap (a recursive structure in the standard library) does not.

Then to insert a child node you will need to use:

*self.children[index] = Some(Box::new(new_tree));
Kevin Reid
  • 37,492
  • 13
  • 80
  • 108
  • Thanks, currently don't have access to my computer, so when I do, I'll try it out. I had tried boxing the data, but it gave me errors that it needed the Copy trait, but when I tried to implement it or Clone, I would get errors about implementing it for arbitrary types and how it already implemented Drop. Guess I didn't try it with the dereference. – J. Henriksson Jul 14 '21 at 13:31
  • 1
    @J.Henriksson When the compiler says "doesn't implement Copy", the correct solution is almost never to try to make the type implement Copy, but to either clone it, or avoid moving it when you didn't mean to. – Kevin Reid Jul 14 '21 at 14:09
  • OK, got it working, putting final changes down here cause "the edit queue is full". First, changing to `Option>>` worked, but `*self.children[index] = Some(Box::new(new_tree));` didn't. I had to change that to `self.children[index].insert(Box::new(new_tree));`. I also had to change it from `children: [None; 8]` to `children: [None, None, None, None, None, None, None, None]` since `None` doesn't implement `Copy`. But it runs now. Thanks for the help and the pointers on how to go about this! – J. Henriksson Jul 14 '21 at 16:38