Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
godmar opened this issue Jul 22, 2021 · 5 comments
Open

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

godmar opened this issue Jul 22, 2021 · 5 comments

Comments

@godmar
Copy link

godmar commented Jul 22, 2021

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?

@Amanieu
Copy link
Owner

Amanieu commented Jul 22, 2021

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.

@godmar
Copy link
Author

godmar commented Jul 22, 2021

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?

@Amanieu
Copy link
Owner

Amanieu commented Jul 22, 2021

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.

@ibraheemdev
Copy link

@godmar
Copy link
Author

godmar commented Jul 23, 2021

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.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants