From 0fae530a5b2e0566064548ed59f4918d424fd01b Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Tue, 22 Oct 2024 10:38:26 -0700 Subject: [PATCH] [unsafe-fields] Add README.md (#1961) Release 0.2.1. Makes progress on #1931 gherrit-pr-id: Icc9b6841e66c961989862ff6fb3b4f5140c54513 --- README.md | 2 +- ci/check_readme.sh | 4 +- tools/generate-readme/src/main.rs | 2 +- unsafe-fields/Cargo.toml | 2 +- unsafe-fields/README.md | 112 ++++++++++++++++++++++++++++++ unsafe-fields/src/lib.rs | 11 ++- 6 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 unsafe-fields/README.md diff --git a/README.md b/README.md index 358a4a6a7e..6fa9a240f5 100644 --- a/README.md +++ b/README.md @@ -201,4 +201,4 @@ Zerocopy uses [GitHub Releases]. ## Disclaimer -Disclaimer: Zerocopy is not an officially supported Google product. +Disclaimer: This is not an officially supported Google product. diff --git a/ci/check_readme.sh b/ci/check_readme.sh index 241128d0d0..413f5a866d 100755 --- a/ci/check_readme.sh +++ b/ci/check_readme.sh @@ -16,4 +16,6 @@ set -eo pipefail cargo install -q cargo-readme --version 3.2.0 diff <(cargo -q run --manifest-path tools/Cargo.toml -p generate-readme) README.md >&2 -exit $? + +cd unsafe-fields +diff <(cargo -q run --manifest-path ../tools/Cargo.toml -p generate-readme) README.md >&2 diff --git a/tools/generate-readme/src/main.rs b/tools/generate-readme/src/main.rs index 8945caea7b..908231608b 100644 --- a/tools/generate-readme/src/main.rs +++ b/tools/generate-readme/src/main.rs @@ -27,7 +27,7 @@ made in the doc comment on `src/lib.rs` or in `tools/generate-readme`. const DISCLAIMER_FOOTER: &str = "\ ## Disclaimer -Disclaimer: Zerocopy is not an officially supported Google product.\ +Disclaimer: This is not an officially supported Google product.\ "; fn main() { diff --git a/unsafe-fields/Cargo.toml b/unsafe-fields/Cargo.toml index adc98bbff5..43ab479958 100644 --- a/unsafe-fields/Cargo.toml +++ b/unsafe-fields/Cargo.toml @@ -8,7 +8,7 @@ [package] name = "unsafe-fields" -version = "0.2.0" +version = "0.2.1" edition = "2021" description = "Make it unsafe to access or modify fields with safety invariants" license = "BSD-2-Clause OR Apache-2.0 OR MIT" diff --git a/unsafe-fields/README.md b/unsafe-fields/README.md new file mode 100644 index 0000000000..e004e263b2 --- /dev/null +++ b/unsafe-fields/README.md @@ -0,0 +1,112 @@ + + +# 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` 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](crate#limitations). + +[immutable]: zerocopy_0_8::Immutable + +## Examples + +```rust +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 { + 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: + +```rust,compile_fail,E0308 +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: + +```rust +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. diff --git a/unsafe-fields/src/lib.rs b/unsafe-fields/src/lib.rs index 65bdb76b9f..06566189e1 100644 --- a/unsafe-fields/src/lib.rs +++ b/unsafe-fields/src/lib.rs @@ -6,6 +6,11 @@ // This file may not be copied, modified, or distributed except according to // those terms. +// After updating the following doc comment, make sure to run the following +// command to update `README.md` based on its contents: +// +// cargo -q run --manifest-path ../tools/Cargo.toml -p generate-readme > README.md + //! Support for unsafe fields. //! //! This crate provides the [`unsafe_fields!`] macro, which can be used to mark @@ -28,7 +33,7 @@ //! //! # Examples //! -//! ``` +//! ```rust //! use unsafe_fields::{unsafe_fields, Unsafe}; //! //! unsafe_fields! { @@ -57,7 +62,7 @@ //! //! Attempting to swap unsafe fields of the same type is prevented: //! -//! ```compile_fail,E0308 +//! ```rust,compile_fail,E0308 //! use unsafe_fields::{unsafe_fields, Unsafe}; //! //! unsafe_fields! { @@ -84,7 +89,7 @@ //! Note that we cannot prevent `Unsafe`s from being swapped between the same //! field in instances of the same type: //! -//! ``` +//! ```rust //! use unsafe_fields::{unsafe_fields, Unsafe}; //! //! unsafe_fields! {