is_impl/lib.rs
1//! a macro to check that a value conforms to a type
2
3/// Checks that an expression `ex` conforms to type `type` at compile time. This should have no runtime cost
4/// and can be used with trait types when adding `dyn`.
5///
6/// ## Short example: check inline that a value implements the `Debug` trait
7/// ```rust
8///# use is_impl::*;
9///# use std::fmt::Debug;
10/// let x = is_impl!(dyn Debug, 2);
11/// ```
12///
13/// ## More elaborate example: making sense of a complex future pipeline
14/// ```
15/// # extern crate futures;
16/// # extern crate futures01;
17/// extern crate is_impl;
18/// # use crate::futures::compat::Future01CompatExt;
19/// # use crate::futures::future::Future as Future03;
20/// # use crate::futures::FutureExt;
21/// # use crate::futures::TryFutureExt;
22/// # use crate::futures01::future::Future as Future01;
23/// use is_impl::*;
24/// # // some futures 0.1 library that spawns a future
25/// # fn spawn<E>(_value: impl futures01::Future<Item = E>) {}
26/// # // some futures 0.1 library that makes a request
27/// # fn request(_test: &str) -> impl futures01::Future<Item = i32, Error = ()> {
28/// # futures01::future::ok(1)
29/// # }
30/// # // some futures 0.3 library
31/// # fn transform(
32/// # x: impl futures::future::Future<Output = i32>,
33/// # ) -> impl futures::future::Future<Output = i32> {
34/// # x.map(|value| value * 2)
35/// # }
36///
37/// // assert (inline) the future type
38/// let req = is_impl!(dyn Future01<Item=i32, Error=()>, request("something"));
39/// // assert (inline) that we are in new futures and have successfully gotten rid of the unit error
40/// let new_future = is_impl!(dyn Future03<Output = i32>, req.compat().into_future().map(|x| x.unwrap()));
41/// // assert (inline) the transformed type
42/// let transformed = is_impl!(dyn Future03<Output = i32>, transform(new_future));
43/// // assert (inline) that we are back in futures 0.1 land with an error
44/// let res = is_impl!(dyn Future01<Item=i32, Error=()>, transformed.unit_error().compat());
45/// // do the thing!
46/// spawn(res);
47/// ```
48///
49/// Usually I use `is_impl!` to figure out where the types don't align during development, and then remove the assertions
50/// again once I am happy with the code. But since the macro does not have a runtime cost you can also leave them in.
51///
52#[macro_export]
53macro_rules! is_impl {
54 ($type:ty, $ex:expr) => {{
55 if false {
56 let _: Box<$type> = Box::new($ex);
57 unreachable!();
58 }
59 $ex
60 }};
61}
62
63#[cfg(test)]
64mod tests {
65
66 trait A {}
67
68 struct Foo;
69
70 // struct Bar;
71
72 impl A for Foo {}
73 #[test]
74 fn basic_usage() {
75 let foo: Foo = Foo;
76 let _foo: Foo = is_impl!(Foo, foo);
77 // does not compile
78 // let bar: Bar = Bar;
79 // let bar: Bar = is_impl!(Foo, bar);
80 }
81
82}