pinned-aliasable

Unboxed aliasable values based on Pin.

In Rust, it is currently impossible to soundly create unboxed self-referencing, or externally-referenced, types - see this document for details. However, futures generated by async blocks need to be self-referencing, and this makes them technically unsound. So to avoid miscompilations, Rust has inserted a temporary loophole: No unique references to !Unpin types will actually be annotated with noalias, preventing the compiler from making optimizations based on the pointed-to types being not self-referential.

This is a huge hack. Not all self-referential types are !Unpin, and some !Unpin types would actually work with noalias. Ultimately, the solution will be to provide an Aliasable<T> type in libcore that prevents any parent containers from being annotated with noalias, but unfortunately that doesn't exist yet.

As a workaround, this crate provides an [Aliasable<T>] type that doesn't cause miscompilations today by being !Unpin, and is future-compatible with the hypothetical Aliasable type in libcore. Additionally, to avoid Miri giving errors, it is substituted for a boxed value when run using it. When Aliasable is finally added to the language itself, I will release a new version of this crate based on it and yank all previous versions.

Examples

A pair type:

```rust use core::pin::Pin; use core::cell::Cell;

use pinnedaliasable::Aliasable; use pinprojectlite::pinproject; use pinutils::pinmut;

pin_project! { pub struct Pair { #[pin] inner: Aliasable, } } struct PairInner { value: u64, other: Cell>, } impl Drop for PairInner { fn drop(&mut self) { if let Some(other) = self.other.get() { other.other.set(None); } } }

impl Pair { pub fn new(value: u64) -> Self { Self { inner: Aliasable::new(PairInner { value, other: Cell::new(None), }) } } pub fn get(self: Pin<&Self>) -> u64 { self.project_ref().inner.get().other.get().unwrap().value } }

pub fn linkup(left: Pin<&Pair>, right: Pin<&Pair>) { let left = unsafe { left.projectref().inner.getextended() }; let right = unsafe { right.projectref().inner.get_extended() }; left.other.set(Some(right)); right.other.set(Some(left)); }

fn main() { let pair1 = Pair::new(10); let pair2 = Pair::new(20); pinmut!(pair1); pinmut!(pair2);

link_up(pair_1.as_ref(), pair_2.as_ref());

println!("Pair 2 value: {}", pair_1.as_ref().get());
println!("Pair 1 value: {}", pair_2.as_ref().get());

} ```

License: MIT