devela/code/util/asserts/static/
impl.rs

1// devela::code::util::asserts::static::impl
2
3/// Returns `true` if the type does implement a logical trait expression.
4///
5/// # Examples
6///
7/// One can mimic `assert_impl!` using this macro:
8///
9/// ```
10/// # #[macro_use] extern crate devela; fn main() {}
11/// const CONDITION: bool = does_impl!(u32: From<u8>);
12///
13/// const_assert!(CONDITION);
14/// ```
15#[macro_export(local_inner_macros)]
16#[cfg_attr(cargo_primary_package, doc(hidden))]
17macro_rules! does_impl {
18    ($ty:ty: $($trait_expr:tt)+) => {
19        _does_impl!($ty: $($trait_expr)+).value()
20    };
21}
22
23/// Returns `True` or `False` depending on whether the given type implements the
24/// given trait boolean expression. Can be used in const contexts if it doesn't
25/// depend on outer generic parameters.
26///
27/// This is the core of `assert_impl`.
28#[doc(hidden)]
29#[macro_export(local_inner_macros)]
30macro_rules! _does_impl {
31    ($ty:ty: $($rest:tt)*) => {{
32        #[allow(unused_imports)]
33        use $crate::{True, False, PhantomData, Deref};
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}