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}