is_trait/lib.rs
1//! This crate adds a `is_trait!` macro for getting a runtime value for if a type implements a trait
2//! This can be useful for test, where you can have a test fail instead of getting a compile error
3//! Example:
4//! ```should_panic
5//! use is_trait::is_trait;
6//!
7//! struct Thing;
8//! struct OtherThing;
9//! trait SomeTrait {}
10//! impl SomeTrait for Thing {}
11
12//! assert!(is_trait!(Thing, SomeTrait));
13//! assert!(is_trait!(OtherThing, SomeTrait)); // FAILS
14//! ```
15
16/// [See crate level docs for usage](index.html)
17///
18/// Under the hood, this macro creates trait `A` and struct `B<T>`
19///
20/// `B<T>` implements [`std::ops::Deref`] to `()`
21///
22/// `A` is implemented for `()` to return `false`
23///
24/// `A` is implemented for `B<T>` where `T: SomeTrait` to return true
25///
26/// We then call `A` on `B::<SomeType>`.
27/// Because of rust dereferencing rules, if `SomeType` is `SomeTrait`, then we call `A` on `B<T>` which is true.
28/// However, if `SomeType` is not `SomeTrait`, we dereference `B<T>` into `()` and call `A` on that, which is false
29#[macro_export]
30macro_rules! is_trait {
31 ($type:ty, $trait:path) => {{
32 trait A {
33 fn is(&self) -> bool;
34 }
35
36 struct B<T: ?Sized>(core::marker::PhantomData<T>);
37
38 impl<T: ?Sized> core::ops::Deref for B<T> {
39 type Target = ();
40 fn deref(&self) -> &Self::Target {
41 &()
42 }
43 }
44
45 impl<T: ?Sized> A for B<T>
46 where
47 T: $trait,
48 {
49 fn is(&self) -> bool {
50 true
51 }
52 }
53
54 impl A for () {
55 fn is(&self) -> bool {
56 false
57 }
58 }
59
60 B::<$type>(core::marker::PhantomData).is()
61 }};
62}
63
64/// Like [`is_trait`] but uses const trait impls
65#[macro_export]
66macro_rules! const_is_trait {
67 ($type:ty, $trait:path) => {{
68 trait A {
69 fn is(&self) -> bool;
70 }
71
72 struct B<T: ?Sized>(core::marker::PhantomData<T>);
73
74 impl<T: ?Sized> const core::ops::Deref for B<T> {
75 type Target = ();
76 fn deref(&self) -> &Self::Target {
77 &()
78 }
79 }
80
81 impl<T: ?Sized> const A for B<T>
82 where
83 T: $trait,
84 {
85 fn is(&self) -> bool {
86 true
87 }
88 }
89
90 impl const A for () {
91 fn is(&self) -> bool {
92 false
93 }
94 }
95
96 B::<$type>(core::marker::PhantomData).is()
97 }};
98}