/// Returns `true` if the type does implement a logical trait expression. /// /// # Examples /// /// One can mimic `assert_impl!` using this macro: /// /// ``` /// # #[macro_use] extern crate static_assertions; fn main() {} /// const CONDITION: bool = does_impl!(u32: From<u8>); /// /// const_assert!(CONDITION); /// ``` #[macro_export(local_inner_macros)] macro_rules! does_impl { ($ty:ty: $($trait_expr:tt)+) => { _does_impl!($ty: $($trait_expr)+).value() }; } /// Returns `True` or `False` depending on whether the given type implements the /// given trait boolean expression. Can be used in const contexts if it doesn't /// depend on outer generic parameters. /// /// This is the core of `assert_impl`. #[doc(hidden)] #[macro_export(local_inner_macros)] macro_rules! _does_impl { ($ty:ty: $($rest:tt)*) => {{ #[allow(unused_imports)] use $crate::{ _bool::{True, False}, _core::{marker::PhantomData, ops::Deref}, }; // Fallback trait that returns false if the type does not implement a // given trait. trait DoesntImpl { const DOES_IMPL: False = False; } impl<T: ?Sized> DoesntImpl for T {} // Construct an expression using `True`/`False` and their operators, // that corresponds to the provided expression. *_does_impl!(@boolexpr($ty,) $($rest)*) }}; (@boolexpr($($args:tt)*) ($($expr:tt)*)) => { _does_impl!(@boolexpr($($args)*) $($expr)*) }; (@boolexpr($($args:tt)*) !($($expr:tt)*)) => { _does_impl!(@boolexpr($($args)*) $($expr)*).not() }; (@boolexpr($($args:tt)*) ($($left:tt)*) | $($right:tt)*) => {{ let left = _does_impl!(@boolexpr($($args)*) $($left)*); let right = _does_impl!(@boolexpr($($args)*) $($right)*); left.or(right) }}; (@boolexpr($($args:tt)*) ($($left:tt)*) & $($right:tt)*) => {{ let left = _does_impl!(@boolexpr($($args)*) $($left)*); let right = _does_impl!(@boolexpr($($args)*) $($right)*); left.and(right) }}; (@boolexpr($($args:tt)*) !($($left:tt)*) | $($right:tt)*) => {{ _does_impl!(@boolexpr($($args)*) (!($($left)*)) | $($right)*) }}; (@boolexpr($($args:tt)*) !($($left:tt)*) & $($right:tt)*) => {{ _does_impl!(@boolexpr($($args)*) (!($($left)*)) & $($right)*) }}; (@boolexpr($($args:tt)*) !$left:ident | $($right:tt)*) => {{ _does_impl!(@boolexpr($($args)*) !($left) | $($right)*) }}; (@boolexpr($($args:tt)*) !$left:ident & $($right:tt)*) => {{ _does_impl!(@boolexpr($($args)*) !($left) & $($right)*) }}; (@boolexpr($($args:tt)*) $left:ident | $($right:tt)*) => { _does_impl!(@boolexpr($($args)*) ($left) | $($right)*) }; (@boolexpr($($args:tt)*) $left:ident & $($right:tt)*) => {{ _does_impl!(@boolexpr($($args)*) ($left) & $($right)*) }}; (@boolexpr($($args:tt)*) !$expr:ident) => { _does_impl!(@boolexpr($($args)*) !($expr)) }; (@boolexpr($($args:tt)*) !$expr:path) => { _does_impl!(@boolexpr($($args)*) !($expr)) }; (@boolexpr($($args:tt)*) $expr:ident) => { _does_impl!(@base($($args)*) $expr) }; (@boolexpr($($args:tt)*) $expr:path) => { _does_impl!(@base($($args)*) $expr) }; (@base($ty:ty, $($args:tt)*) $($trait:tt)*) => {{ // Base case: computes whether `ty` implements `trait`. struct Wrapper<T: ?Sized>(PhantomData<T>); #[allow(dead_code)] impl<T: ?Sized + $($trait)*> Wrapper<T> { const DOES_IMPL: True = True; } // If `$type: $trait`, the `_does_impl` inherent method on `Wrapper` // will be called, and return `True`. Otherwise, the trait method will // be called, which returns `False`. &<Wrapper<$ty>>::DOES_IMPL }}; }