0

I'm building a circular linked list using an arena for the nodes.

If I use a struct like the following it works fine:

struct Node<'a> {
  next: Cell<Option<&'a Edge<'a>>>
}

let f = Node { next: Cell::new(None) };
f.next.set(&f);

Having to use an Option<&'a Edge> is a pain because having the next pointer be None is not a state that I want to have representable in the data structure.

Ideally, I could just use &'a Edge but creating an initial one node list is difficult.

One option is the following:

struct Edge<'a> {
  next: Cell<&'a Edge<'a>>
}

let u: MaybeUninit<Edge> = MaybeUninit::uninit();
let next = unsafe { &(*u.as_ptr()) };
let s = Edge { next: Cell::new(next)};
s.next.set(&s);

That does the job and miri with -Zmiri-track-raw-pointers doesn't complain about any undefined behaviour. However, https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.as_ptr suggests that creating a reference to uninitialized memory is undefined behaviour.

Is there an alternative method of initializing that Edge that I can be more certain isn't undefined behaviour?

Jeff Muizelaar
  • 574
  • 2
  • 8
  • 1
    "*but without having the Option it seems a lot harder... this is a difficult task because even creating a reference to uninitialized memory is undefined behaviour.*" And this is why we have Option. But maybe you want to know how to implement a circular linked list of one element? – Schwern Apr 02 '22 at 19:30
  • You can use [ouroboros](https://github.com/joshua-maros/ouroboros) or [pin](https://doc.rust-lang.org/std/pin/index.html). See [Self Referential Structs in Rust (Part 1)](https://dev.to/arunanshub/self-referential-structs-in-rust-33cm). – Schwern Apr 02 '22 at 19:39
  • `Edge2` already implements a circular linked list of one element. But using it is unnecessarily painful because the `Option` means you have to handle the None case when it's not actually a value that I want to be represented. – Jeff Muizelaar Apr 03 '22 at 00:36
  • `ouroboros` and `pin` don't seem helpful for what I'm trying to accomplish here. `ouroboros` boxes fields and seems to about having references to other fields in the same struct instead of a reference to the actual struct. I also don't see how `pin` would be helpful. The self borrow already prevents the struct from being moved just fine. – Jeff Muizelaar Apr 03 '22 at 00:43
  • No. You should use raw pointers (or better, not use self-referential structs). And creating a reference to uninitialized memory is indeed UB, it's well-known Miri doesn't check that. – Chayim Friedman Apr 03 '22 at 01:19

0 Answers0