Lifetime for &mut to parent struct

Hello all,

I've got a struct that I need to keep a reference to it's parent. In effect it forms a stack. Here is a simplified version of the struct and methods

use std::ptr::NonNull;

MyStruct<'a> {
  some_data: &'a DataStuff,
  parent: Option<NonNull<MyStruct<'a>>
}

impl<'a> MyStruct<'a> {
  pub fn new(some_data: &'a DataStuff) -> Self {
    Self {
      some_data,
      parent: None,
    }
  }

  pub fn child(parent: &mut MyStruct<'a>) -> Self {
    Self {
       some_data: parent.someData,
       parent: Some(NonNull::from(parent))
    }
  }

  // we need to do something with my struct but we also need to process the children
  pub fn process_1(&mut self) {
    self.do_stuff();
    self.process_2();
  }

  // we create a child with what is now a NonNull to what will be it's parent and process
  pub fn process_2(&mut self) {
     let child = MyStruct(&mut *self)
     child.process_1();
  }

  fn do_stuff(&mut self) {
    match self.parent {
       Some(parent) => { /* do a thing with parent */ }
       None => { /* do something else if we're the base struct */}
    }
  }
}

So right now I'm using a NonNull pointer because it just ignores lifetimes, but after looking at this for a while it seem to me in this example that child in process_2 has exclusive mutable access to &mut self for the length of the method before it gets cleaned up. It feel I should be able to go with the safer &mut MyStruct<'a> instead of a NonNull. I tried changing my struct to something like

MyStruct<'a, 'p> {
  someData: &'a DataStuff,
  parent: Option<&'p mut MyStruct<'a, 'p>>
}

But I then get lifetime conflicts. I think the problem is it tries to take 'p from the parent is too long since that the lifetime outlives the child. If it's not possible, I'm fine with the NonNull since I already have plenty of tests that show it works and it fairly easy to reason that it isn't mutating anything that disagrees with rust ownership semantics. Anyways appreciate any help on this!

This is called a self-referential struct (the parent is the self-referential struct in this case), and self-referential structs are impossible in Rust — at least using ordinary references.

One option is to use Rc or Arc.

4 Likes

So the parent doesn't references the child just the child to the parent. The child is only a local variable in the method body. Is that still the case? It seems the pointer may be my best bet or an Rc if I want the safe route.

Maybe using ancestor instead of parent can help distinguish when relationship is one way.

Your NonNull code fails to be safe; as soon as call to child finishes, the parent is no longer borrowed, so can be changed or dropped.

Without mut your reference change is valid. It's not possible to do with mut. The lifetimes belonging to the structure being referred to are invariant.