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}