blob: 83545ca49fe17d204fc1c07ee05695100d101f15 [file] [log] [blame]
/// Asserts that the type implements exactly one in a set of traits.
///
/// Related:
/// - [`assert_impl_any!`]
/// - [`assert_impl_all!`]
/// - [`assert_impl_not_all!`]
/// - [`assert_impl_not_any!`]
///
/// # Examples
///
/// Given some type `Foo`, it is expected to implement either `Snap`, `Crackle`,
/// or `Pop`:
///
/// ```compile_fail
/// # use static_assertions::assert_impl_one; fn main() {}
/// struct Foo;
///
/// trait Snap {}
/// trait Crackle {}
/// trait Pop {}
///
/// assert_impl_one!(Foo: Snap, Crackle, Pop);
/// ```
///
/// If _only_ `Crackle` is implemented, the assertion passes:
///
/// ```
/// # use static_assertions::assert_impl_one; fn main() {}
/// # struct Foo;
/// # trait Snap {}
/// # trait Crackle {}
/// # trait Pop {}
/// impl Crackle for Foo {}
///
/// assert_impl_one!(Foo: Snap, Crackle, Pop);
/// ```
///
/// If `Snap` or `Pop` is _also_ implemented, the assertion fails:
///
/// ```compile_fail
/// # use static_assertions::assert_impl_one; fn main() {}
/// # struct Foo;
/// # trait Snap {}
/// # trait Crackle {}
/// # trait Pop {}
/// # impl Crackle for Foo {}
/// impl Pop for Foo {}
///
/// assert_impl_one!(Foo: Snap, Crackle, Pop);
/// ```
///
/// [`assert_impl_any!`]: macro.assert_impl_any.html
/// [`assert_impl_all!`]: macro.assert_impl_all.html
/// [`assert_impl_not_all!`]: macro.assert_not_impl_all.html
/// [`assert_impl_not_any!`]: macro.assert_not_impl_any.html
#[macro_export]
macro_rules! assert_impl_one {
($x:ty: $($t:path),+ $(,)?) => {
const _: fn() = || {
// Generic trait that must be implemented for `$x` exactly once.
trait AmbiguousIfMoreThanOne<A> {
// Required for actually being able to reference the trait.
fn some_item() {}
}
// Creates multiple scoped `Token` types for each trait `$t`, over
// which a specialized `AmbiguousIfMoreThanOne<Token>` is
// implemented for every type that implements `$t`.
$({
#[allow(dead_code)]
struct Token;
impl<T: ?Sized + $t> AmbiguousIfMoreThanOne<Token> for T {}
})+
// If there is only one specialized trait impl, type inference with
// `_` can be resolved and this can compile. Fails to compile if
// `$x` implements more than one `AmbiguousIfMoreThanOne<Token>` or
// does not implement any at all.
let _ = <$x as AmbiguousIfMoreThanOne<_>>::some_item;
};
};
}
/// Asserts that the type implements _all_ of the given traits.
///
/// See [`assert_impl_not_all!`] for achieving the opposite effect.
///
/// # Examples
///
/// This can be used to ensure types implement auto traits such as [`Send`] and
/// [`Sync`], as well as traits with [blanket `impl`s][blanket].
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_impl_all!(u32: Copy, Send);
/// assert_impl_all!(&str: Into<String>);
/// ```
///
/// The following example fails to compile because raw pointers do not implement
/// [`Send`] since they cannot be moved between threads safely:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_impl_all!(*const u8: Send);
/// ```
///
/// [`assert_impl_not_all!`]: macro.assert_not_impl_all.html
/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
/// [blanket]: https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
#[macro_export(local_inner_macros)]
macro_rules! assert_impl_all {
($ty:ty: $($traits:path),+ $(,)?) => {
assert_impl!($ty: $( ($traits) )&+);
};
}
/// Asserts that the type implements _any_ of the given traits.
///
/// See [`assert_impl_not_any!`] for achieving the opposite effect.
///
/// # Examples
///
/// `u8` cannot be converted from `u16`, but it can be converted into `u16`:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_impl_any!(u8: From<u16>, Into<u16>);
/// ```
///
/// The unit type cannot be converted from `u8` or `u16`, but it does implement
/// [`Send`]:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_impl_any!((): From<u8>, From<u16>, Send);
/// ```
///
/// The following example fails to compile because raw pointers do not implement
/// [`Send`] or [`Sync`] since they cannot be moved or shared between threads
/// safely:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_impl_any!(*const u8: Send, Sync);
/// ```
///
/// [`assert_impl_not_any!`]: macro.assert_not_impl_any.html
/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
#[macro_export(local_inner_macros)]
macro_rules! assert_impl_any {
($ty:ty: $($traits:path),+ $(,)?) => {
assert_impl!($ty: $( ($traits) )|+);
};
}
/// Asserts that the type does **not** implement _all_ of the given traits.
///
/// This can be used to ensure types do not implement auto traits such as
/// [`Send`] and [`Sync`], as well as traits with [blanket `impl`s][blanket].
///
/// Note that the combination of all provided traits is required to not be
/// implemented. If you want to check that none of multiple traits are
/// implemented you should invoke [`assert_impl_not_any!`] instead.
///
/// # Examples
///
/// Although `u32` implements `From<u16>`, it does not implement `Into<usize>`:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_impl_not_all!(u32: From<u16>, Into<usize>);
/// ```
///
/// The following example fails to compile since `u32` can be converted into
/// `u64`.
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_impl_not_all!(u32: Into<u64>);
/// ```
///
/// The following compiles because [`Cell`] is not both [`Sync`] _and_ [`Send`]:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// use std::cell::Cell;
///
/// assert_impl_not_all!(Cell<u32>: Sync, Send);
/// ```
///
/// But it is [`Send`], so this fails to compile:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// # std::cell::Cell;
/// assert_impl_not_all!(Cell<u32>: Send);
/// ```
///
/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
/// [`assert_impl_not_any!`]: macro.assert_impl_not_any.html
/// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html
/// [blanket]: https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
#[macro_export(local_inner_macros)]
macro_rules! assert_impl_not_all {
($ty:ty: $($traits:path),+ $(,)?) => {
assert_impl!($ty: !( $( ($traits) )&+ ));
};
}
/// Asserts that the type does **not** implement _all_ of the given traits.
///
/// This macro has been deprecated in favor of
/// [`assert_impl_not_all!`](macro.assert_impl_not_all.html).
#[deprecated(
since = "1.2.0",
note = "Please use the 'assert_impl_not_all' macro instead"
)]
#[macro_export(local_inner_macros)]
macro_rules! assert_not_impl_all {
($($t:tt)*) => {
assert_impl_not_all!($($t)*);
};
}
/// Asserts that the type does **not** implement _any_ of the given traits.
///
/// This can be used to ensure types do not implement auto traits such as
/// [`Send`] and [`Sync`], as well as traits with [blanket `impl`s][blanket].
///
/// This macro causes a compilation failure if any of the provided individual
/// traits are implemented for the type. If you want to check that a combination
/// of traits is not implemented you should invoke [`assert_impl_not_all!`]
/// instead. For single traits both macros behave the same.
///
/// # Examples
///
/// If `u32` were to implement `Into` conversions for `usize` _and_ for `u8`,
/// the following would fail to compile:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_impl_not_any!(u32: Into<usize>, Into<u8>);
/// ```
///
/// This is also good for simple one-off cases:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_impl_not_any!(&'static mut u8: Copy);
/// ```
///
/// The following example fails to compile since `u32` can be converted into
/// `u64` even though it can not be converted into a `u16`:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_impl_not_any!(u32: Into<u64>, Into<u16>);
/// ```
///
/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
/// [`assert_impl_not_all!`]: macro.assert_impl_not_all.html
/// [blanket]: https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
#[macro_export(local_inner_macros)]
macro_rules! assert_impl_not_any {
($ty:ty: $($traits:path),+ $(,)?) => {
assert_impl!($ty: !( $( ($traits) )|+ ));
};
}
/// Asserts that the type does **not** implement _any_ of the given traits.
///
/// This macro has been deprecated in favor of
/// [`assert_impl_not_any!`](macro.assert_impl_not_any.html).
#[deprecated(
since = "1.2.0",
note = "Please use the 'assert_impl_not_any' macro instead"
)]
#[macro_export(local_inner_macros)]
macro_rules! assert_not_impl_any {
($($t:tt)*) => {
assert_impl_not_any!($($t)*);
};
}
/// Asserts that the type implements a logical trait expression.
///
/// This macro causes a compilation failure if the expression is not satisfied.
///
/// See [`does_impl!`](macro.does_impl.html) for simply getting a [`bool`] from
/// this condition without asserting it.
///
/// # Syntax
///
/// ```skip
/// assert_impl!(<type>: <trait_expr>);
/// assert_impl!(for(<type>: <bounds>) <type>: <trait_expr>);
/// ```
///
/// where:
///
/// - `<type>` is a type (that must not depend on a generic parameter)
///
/// - `<trait_expr>` is an expression made out of trait names, combined with `!`
/// for negation, `&` for conjunction, `|` for disjunction and parentheses for
/// grouping.
///
/// - `<bounds>` is a trait bounds expression.
///
/// For technical reasons:
///
/// - Traits (like `Into<u8>`) that are not a single identifier must be
/// surrounded by parentheses.
///
/// - The usual operator priority is not respected: `x & y | z` is parsed as
/// `x & (y | z)`.
///
/// # Examples
///
/// If `u32` were to implement `Into` conversions for `usize` _and_ for `u8`,
/// the following would fail to compile:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_impl!(u32: !((Into<usize>) & (Into<u8>)));
/// ```
///
/// Check that a type is [`Send`] but not [`Sync`].
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// use std::cell::Cell;
///
/// assert_impl!(Cell<u32>: Send & !Sync);
/// ```
///
/// Check simple one-off cases:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_impl!(&'static mut u8: !Copy);
/// ```
///
/// Check that a type is _always_ [`Clone`] even when its parameter isn't:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// use std::rc::Rc;
///
/// assert_impl!(for(T) Rc<T>: Clone);
/// ```
///
/// The following example fails to compile since `u64` cannot be converted into
/// either `u32` or `u16`:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_impl!(u64: (Into<u32>) | (Into<u16>));
/// ```
///
/// [`bool`]: https://doc.rust-lang.org/std/primitive.bool.html
/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
/// [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html
#[macro_export(local_inner_macros)]
macro_rules! assert_impl {
(for($($generic:tt)*) $ty:ty: $($rest:tt)*) => {
const _: () = {
fn assert_impl<$($generic)*>() {
// Construct an expression using `True`/`False` and their
// operators, that corresponds to the provided expression.
let _: $crate::True = $crate::_does_impl!($ty: $($rest)*);
}
};
};
($ty:ty: $($rest:tt)*) => {
// Construct an expression using `True`/`False` and their operators,
// that corresponds to the provided expression.
const _: $crate::True = $crate::_does_impl!($ty: $($rest)*);
};
}