Hacker News new | ask | show | jobs
by idubrov 2811 days ago
FWIW, it is possible to make it a bit more ergonomic:

  pub struct SmartRef<'a> {
    container: &'a Container,
    widget: usize,
  }
  impl <'a> std::ops::Deref for SmartRef<'a> {
    type Target = Widget; // Widget provides non-traversing functionality
    fn deref(&self) -> &Widget {
      &self.container.widgets[self.widget]
    }
  }
  impl <'a> SmartRef<'a> {
    fn children(&'a self) -> impl Iterator<Item = SmartRef<'a>> {
      self.container
        .widgets[self.widget]
        .children.iter().map(move |w| SmartRef { container: self.container, widget: *w })
    }
  }

  fn boo(container: &Container) {
    let root = SmartRef { container, widget: 0 };
    println!("name: {}", root.name);
    for child in root.children() {
      println!("child name: {}", child.name);
    }
  }
(removed GAT remark -- it does not apply here; was thinking about generalizing this with traits)
1 comments

Hmm… that would work, but at the cost of requiring the data to be immutable or use interior mutability. It also removes the size advantage of storing indices over pointers, unless you only make SmartRefs temporarily rather than storing them in your data structures.
Yes, the idea is that you only create them temporarily.

Mutability is also possible to some extent with these "smart" pointers. It gets a bit trickier and less ergonomic, though. See https://play.rust-lang.org/?gist=fbf1c24397e7020c95774bf0906...

Another option would be to store something like "Rc<RefCell<Container>>" instead of "&'a mut Container", in which case you will be able to achieve something that behaves like multiple mutable references (with all the concurrency issues of them).