1 /// Returns `true` if the type does implement a logical trait expression. 2 /// 3 /// # Examples 4 /// 5 /// One can mimic `assert_impl!` using this macro: 6 /// 7 /// ``` 8 /// # #[macro_use] extern crate static_assertions; fn main() {} 9 /// const CONDITION: bool = does_impl!(u32: From<u8>); 10 /// 11 /// const_assert!(CONDITION); 12 /// ``` 13 #[macro_export(local_inner_macros)] 14 macro_rules! does_impl { 15 ($ty:ty: $($trait_expr:tt)+) => { 16 _does_impl!($ty: $($trait_expr)+).value() 17 }; 18 } 19 20 /// Returns `True` or `False` depending on whether the given type implements the 21 /// given trait boolean expression. Can be used in const contexts if it doesn't 22 /// depend on outer generic parameters. 23 /// 24 /// This is the core of `assert_impl`. 25 #[doc(hidden)] 26 #[macro_export(local_inner_macros)] 27 macro_rules! _does_impl { 28 ($ty:ty: $($rest:tt)*) => {{ 29 #[allow(unused_imports)] 30 use $crate::{ 31 _bool::{True, False}, 32 _core::{marker::PhantomData, ops::Deref}, 33 }; 34 35 // Fallback trait that returns false if the type does not implement a 36 // given trait. 37 trait DoesntImpl { 38 const DOES_IMPL: False = False; 39 } 40 impl<T: ?Sized> DoesntImpl for T {} 41 42 // Construct an expression using `True`/`False` and their operators, 43 // that corresponds to the provided expression. 44 *_does_impl!(@boolexpr($ty,) $($rest)*) 45 }}; 46 47 (@boolexpr($($args:tt)*) ($($expr:tt)*)) => { 48 _does_impl!(@boolexpr($($args)*) $($expr)*) 49 }; 50 (@boolexpr($($args:tt)*) !($($expr:tt)*)) => { 51 _does_impl!(@boolexpr($($args)*) $($expr)*).not() 52 }; 53 (@boolexpr($($args:tt)*) ($($left:tt)*) | $($right:tt)*) => {{ 54 let left = _does_impl!(@boolexpr($($args)*) $($left)*); 55 let right = _does_impl!(@boolexpr($($args)*) $($right)*); 56 left.or(right) 57 }}; 58 (@boolexpr($($args:tt)*) ($($left:tt)*) & $($right:tt)*) => {{ 59 let left = _does_impl!(@boolexpr($($args)*) $($left)*); 60 let right = _does_impl!(@boolexpr($($args)*) $($right)*); 61 left.and(right) 62 }}; 63 (@boolexpr($($args:tt)*) !($($left:tt)*) | $($right:tt)*) => {{ 64 _does_impl!(@boolexpr($($args)*) (!($($left)*)) | $($right)*) 65 }}; 66 (@boolexpr($($args:tt)*) !($($left:tt)*) & $($right:tt)*) => {{ 67 _does_impl!(@boolexpr($($args)*) (!($($left)*)) & $($right)*) 68 }}; 69 (@boolexpr($($args:tt)*) !$left:ident | $($right:tt)*) => {{ 70 _does_impl!(@boolexpr($($args)*) !($left) | $($right)*) 71 }}; 72 (@boolexpr($($args:tt)*) !$left:ident & $($right:tt)*) => {{ 73 _does_impl!(@boolexpr($($args)*) !($left) & $($right)*) 74 }}; 75 (@boolexpr($($args:tt)*) $left:ident | $($right:tt)*) => { 76 _does_impl!(@boolexpr($($args)*) ($left) | $($right)*) 77 }; 78 (@boolexpr($($args:tt)*) $left:ident & $($right:tt)*) => {{ 79 _does_impl!(@boolexpr($($args)*) ($left) & $($right)*) 80 }}; 81 (@boolexpr($($args:tt)*) !$expr:ident) => { 82 _does_impl!(@boolexpr($($args)*) !($expr)) 83 }; 84 (@boolexpr($($args:tt)*) !$expr:path) => { 85 _does_impl!(@boolexpr($($args)*) !($expr)) 86 }; 87 (@boolexpr($($args:tt)*) $expr:ident) => { 88 _does_impl!(@base($($args)*) $expr) 89 }; 90 (@boolexpr($($args:tt)*) $expr:path) => { 91 _does_impl!(@base($($args)*) $expr) 92 }; 93 94 (@base($ty:ty, $($args:tt)*) $($trait:tt)*) => {{ 95 // Base case: computes whether `ty` implements `trait`. 96 struct Wrapper<T: ?Sized>(PhantomData<T>); 97 98 #[allow(dead_code)] 99 impl<T: ?Sized + $($trait)*> Wrapper<T> { 100 const DOES_IMPL: True = True; 101 } 102 103 // If `$type: $trait`, the `_does_impl` inherent method on `Wrapper` 104 // will be called, and return `True`. Otherwise, the trait method will 105 // be called, which returns `False`. 106 &<Wrapper<$ty>>::DOES_IMPL 107 }}; 108 } 109