Crates.io | unsafe-alias-cell |
lib.rs | unsafe-alias-cell |
version | 0.0.1 |
source | src |
created_at | 2022-04-21 22:08:19.698672 |
updated_at | 2022-04-22 09:00:50.521917 |
description | Primitive for aliasing mutability |
homepage | |
repository | https://github.com/y86-dev/unsafe-alias-cell |
max_upload_size | |
id | 571919 |
size | 17,447 |
In rust, &mut T
is not normally allowed to refer to aliasing memory. But when writing self
referential structs, one needs aliasing mutable references. This crate provides the
[UnsafeAliasCell<T>
] primitive type. It works similar to the [UnsafeCell<T>
] from the
stdlib:
UnsafeCell<T>
opts-out of the immutability guarantee for&T
: a shared reference&UnsafeCell<T>
may point to data that is being mutated.
[UnsafeAliasCell<T>
] opts-out of the uniqueness guarantee for &mut T
: a unique mutable reference
&mut UnsafeAliasCell<T>
may point to data that is being mutated.
UnsafeAliasCell<T>
]One needs to be careful, when using [UnsafeAliasCell<T>
], because wrong usage leads to undefined
behavior.
Even when using [UnsafeAliasCell<T>
] it is considered undefined behavior to create multiple
aliasing &mut T
. But you are allowed to create multiple aliasing *mut T
/*const T
.
Use [UnsafeAliasCell<T>
] on the part that you intend to alias:
# use unsafe_alias_cell::UnsafeAliasCell;
pub struct SelfReferential {
item: UnsafeAliasCell<i32>,
ptr: *const i32,
}
Now you are allowed to call .get()
on item
and store that pointer in ptr
. For as long as
that SelfReferential
stays pinned, you can use
ptr
to read the item.
Implementing [Unpin
] for any type containing a [UnsafeAliasCell<T>
] is UB.
It is UB to cast the pointer returned by .get()
to
&mut T
, when there exists another pointer (&T
, *const T
or *mut T
) pointing to the inner
of the cell.&T
, when there exists another mutable pointer (*mut T
) pointing to the inner of the cell.Similar to [UnsafeCell<T>
] you need to ensure the aliasing rules for any reference you create
(taken from the stdlib):
'a
(either a &T
or &mut T
reference) that is
accessible by safe code (for example, because you returned it), then you must not access the data
in any way that contradicts that reference for the remainder of 'a
. For example, this means that
if you take the *mut T
from an [UnsafeAliasCell<T>
] and cast it to an &T
, then the data in T
must remain immutable (modulo any [UnsafeCell<U>
]/[UnsafeAliasCell<U>
] data found within T, of
course) until that reference’s lifetime expires. Similarly, if you create a &mut T
reference that
is released to safe code, then you must not access the data within the [UnsafeAliasCell<T>
] until
that reference expires.UnsafeAliasCell<T>
], then any writes must have a proper happens-before relation to all other
accesses (or use atomics).Under the current rules, all types that are !Unpin
do not emit noalias
for &T
and &mut T
in LLVM and are thus able to alias. For [UnsafeAliasCell<T>
] to be sound, it is therefore
required to be contained in only !Unpin
types.