• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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