3 unstable releases
0.2.1 | Oct 22, 2024 |
---|---|
0.2.0 | Oct 21, 2024 |
0.1.0 | Oct 21, 2024 |
#240 in Rust patterns
472 downloads per month
235KB
2.5K
SLoC
unsafe-fields
Support for unsafe fields.
This crate provides the unsafe_fields!
macro, which can be used to mark
fields as unsafe. Unsafe fields automatically have their types wrapped using
the Unsafe
wrapper type. An Unsafe
is intended to be used to for
struct, enum, or union fields which carry safety invariants. All accessors
are unsafe
, which requires any use of an Unsafe
field to be inside an
unsafe
block. One exception is Unsafe::as_ref
, which is available when
the zerocopy_0_8
feature is enabled. See its docs for more information.
An unsafe field has the type Unsafe<O, F, const NAME_HASH: u128>
. O
is
the enclosing type (struct, enum, or union), F
is the type of the field,
and NAME_HASH
is the hash of the field's name. O
prevents swapping
unsafe fields of the same F
type between different enclosing types, and
NAME_HASH
prevents swapping different fields of the same F
type within
the same enclosing type. Note that swapping the same field between instances
of the same type cannot be prevented.
Examples
use unsafe_fields::{unsafe_fields, Unsafe};
unsafe_fields! {
/// A `usize` which is guaranteed to be even.
pub struct EvenUsize {
// INVARIANT: `n` is even.
#[unsafe]
n: usize,
}
}
impl EvenUsize {
/// Constructs a new `EvenUsize`.
///
/// Returns `None` if `n` is odd.
pub fn new(n: usize) -> Option<EvenUsize> {
if n % 2 != 0 {
return None;
}
// SAFETY: We just confirmed that `n` is even.
let n = unsafe { Unsafe::new(n) };
Some(EvenUsize { n })
}
}
Attempting to swap unsafe fields of the same type is prevented:
use unsafe_fields::{unsafe_fields, Unsafe};
unsafe_fields! {
/// A range.
pub struct Range {
// INVARIANT: `lo <= hi`.
#[unsafe]
lo: usize,
#[unsafe]
hi: usize,
}
}
impl Range {
pub fn swap(&mut self) {
// ERROR: Mismatched types
core::mem::swap(&mut self.lo, &mut self.hi);
}
}
Limitations
Note that we cannot prevent Unsafe
s from being swapped between the same
field in instances of the same type:
use unsafe_fields::{unsafe_fields, Unsafe};
unsafe_fields! {
/// A `usize` which is guaranteed to be even.
pub struct EvenUsize {
// INVARIANT: `n` is even.
#[unsafe]
n: usize,
}
}
pub fn swap(a: &mut EvenUsize, b: &mut EvenUsize) {
core::mem::swap(&mut a.n, &mut b.n);
}
Disclaimer
Disclaimer: This is not an officially supported Google product.