diff --git a/assertions/Cargo.toml b/assertions/Cargo.toml new file mode 100644 index 0000000000..36f9beb5e6 --- /dev/null +++ b/assertions/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "assertions" +version = "0.1.0" +authors = ["The Chromium OS Authors"] diff --git a/assertions/src/lib.rs b/assertions/src/lib.rs new file mode 100644 index 0000000000..c53c0c4e49 --- /dev/null +++ b/assertions/src/lib.rs @@ -0,0 +1,47 @@ +// Copyright 2018 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//! Macros that assert properties of code at compile time. +//! +//! A static assertion is particularly appropriate when unsafe code relies on +//! two types to have the same size, or on some type to have a particular size. + +#[doc(hidden)] +pub mod mechanism; + +// Re-export so that these types appear with a more concise name in error +// messages. +#[doc(hidden)] +pub use mechanism::*; + +/// Macro that fails to compile if a given const expression is not true. +/// +/// # Example +/// +/// ```rust +/// extern crate assertions; +/// use assertions::const_assert; +/// +/// fn main() { +/// const_assert!(std::mem::size_of::() == 24); +/// } +/// ``` +/// +/// # Example that fails to compile +/// +/// ```rust,compile_fail +/// extern crate assertions; +/// use assertions::const_assert; +/// +/// fn main() { +/// // fails to compile: +/// const_assert!(std::mem::size_of::() == 8); +/// } +/// ``` +#[macro_export] +macro_rules! const_assert { + ($e:expr) => { + let _: $crate::Assert<[(); $e as bool as usize]>; + }; +} diff --git a/assertions/src/mechanism.rs b/assertions/src/mechanism.rs new file mode 100644 index 0000000000..e14b91a866 --- /dev/null +++ b/assertions/src/mechanism.rs @@ -0,0 +1,34 @@ +// Copyright 2018 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +use std::marker::PhantomData; + +pub struct True; +pub struct False; + +pub trait Expr { + type Value; +} + +impl Expr for [(); 0] { + type Value = False; +} + +impl Expr for [(); 1] { + type Value = True; +} + +// If the macro instantiates this with `T = [(); 1]` then it compiles successfully. +// +// On the other hand if `T = [(); 0]` the user receives an error like the following: +// +// error[E0271]: type mismatch resolving `<[(); 0] as assertions::Expr>::Value == assertions::True` +// --> src/main.rs:5:5 +// | +// 5 | const_assert!(std::mem::size_of::() == 8); +// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `assertions::True`, found struct `assertions::False` +// +pub struct Assert> { + marker: PhantomData, +}