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

Download history 433/week @ 2024-10-19 39/week @ 2024-10-26

472 downloads per month

BSD-2-Clause OR Apache-2.0 OR MIT

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

Dependencies