Amanieu / intrusive-rs

Intrusive collections for Rust

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Q.: Would pinning enable circular doubly-linked lists?

godmar opened this issue · comments

In DESIGN.md you write

Elements in a collection can't have a pointer back to the collection itself since these would become invalid if the collection is moved. C++ doesn't suffer from this limitation because it can adjust these pointers in the move constructor. [...]

This basically means that we have to use NULL-terminated linked lists instead of circular linked lists. It's very slightly slower (depending on who you ask), but generally not a big deal. This same restriction also applies to normal collection types in Rust.

This document was written 4 years ago. Was that before std::pin was introduced?
If so (here's my question) would circular lists be possible if the collection were guaranteed to be pinned?
Would that be a meaningful approach to enable circular lists?

Yes, the design of this crate predates Pin. However I am not a big fan of Pin because I feel that it makes APIs quite unergonomic.

Pinning a LinkedList would allow you to make it a circular linked list. However this would require changing all methods to take self: Pin<&mut Self> or something similar.

Pinning a LinkedList would allow you to make it a circular linked list. However this would require changing all methods to take self: Pin<&mut Self> or something similar.

Wouldn't that still violate Rust's aliasing rules? (if, say, a raw pointer is used - must be used? - to change the interior of the object while a &mut Self is in scope?) Or does Pin<> sort of imply UnsafeCell<T>, e.g., the compiler must assume an object's interior may change?

That's a good point. I'm not actually sure since I'm not too familiar with the exact rules on Pin. I believe this is a concern for self-referential structs in general, see rust-lang/rust#63818.

https://gist.github.com/Darksonn/1567538f56af1a8038ecc3c664a42462

I read this after Amanieu posted the link to the larger discussion. However, tokio doesn't use circular lists at this time, so there is an additional problem, I think.

The immediate problem I've been encountering with my early attempts at implementing a circular linked list is that while it works when I use raw pointers throughout (as it should), it starts failing when I try to keep the collection head/tail in a Rust object and use Rust-style methods that take &mut self due to the uniqueness assumption Rust makes.

When the last element of a list is removed and the circular list is in a state where tail.prev points to the head and head.next points to the tail, the compiler will assume that the address of self.tail.prev is not aliased with the raw pointer that's used to change it, and thus it will generate code under the assumption that it didn't change. At first, I mistakenly believed this to be a compiler bug, but Rust's rules basically follow LLVMs and the interior raw pointer that was used to close the list is not considered to be based on the unique &mut self reference (this is with the more aggressive -Zmutable-noalias=yes on).

I think that at this point I'm looking for the mystical UnsafeAliasedCell or else I may go with a C-style raw pointer implementation for my use case (I'm not aiming for a general purpose linked list the way Amanieu's crate does.)