SHARE
TWEET

Untitled

a guest Oct 21st, 2019 78 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #[macro_export]
  2. macro_rules! assert_impl_any {
  3.     ($x:ty: $($t:path),+ $(,)?) => {
  4.         const _: fn() = || {
  5.             use core::marker::PhantomData;
  6.             use core::ops::Deref;
  7.  
  8.             struct AssertAnyTraitNoTrait;
  9.             let next = AssertAnyTraitNoTrait;
  10.  
  11.             // Ensures that blanket traits can't impersonate the method.
  12.             struct AssertAnyTraitToken;
  13.             $(
  14.                 let next = {
  15.                     struct Wrapper<T, N>(PhantomData<T>, N);
  16.                     // If the `__static_assert__has_any_trait` method for this wrapper can't be called then
  17.                     // the compiler will insert a deref and try again. This forwards the compilers next
  18.                     // attempt to the previous wrapper.
  19.                     impl<T, N> Deref for Wrapper<T, N> {
  20.                         type Target = N;
  21.                         fn deref(&self) -> &Self::Target {
  22.                             &self.1
  23.                         }
  24.                     }
  25.                     // This impl has a trait bound on $x so the method can only be called if $x implements $t.
  26.                     impl<T: $t, N> Wrapper<T, N> {
  27.                         #[allow(non_snake_case)]
  28.                         // The `TOKEN` generic ensures that a method on a blanket trait can't be generic and therefore accept the `AssertAnyTraitToken`.
  29.                         fn __static_assert__has_any_trait<TOKEN>(&self, _: AssertAnyTraitToken) {}
  30.                     }
  31.                     Wrapper::<$x, _>(PhantomData, next)
  32.                 };
  33.             )+
  34.             // Attempt to find a `__static_assert__has_any_trait` method that can actually be called.
  35.             next.__static_assert__has_any_trait::<()>(AssertAnyTraitToken);
  36.         };
  37.     };
  38. }
  39.  
  40. mod tests {
  41.     #[test]
  42.     fn should_compile() {
  43.         assert_impl_any!((): Send, Sync);
  44.         assert_impl_any!((): Send, From<u8>);
  45.     }
  46.    
  47.     /// The macro isn't perfect and a trait with the correct method name can interfere with the macro.
  48.     ///
  49.     /// This tests the case with interference where the macro should normally fail. The interference still causes the macro to fail so this doesn't really matter.
  50.     ///
  51.     /// ```compile_fail
  52.     /// use playground::assert_impl_any;
  53.     ///
  54.     /// trait Interfere {
  55.     ///     #[allow(non_snake_case)]
  56.     ///     fn __static_assert__has_any_trait<A>(&self, token: A) {}
  57.     /// }
  58.     /// impl<T> Interfere for T {}
  59.     ///
  60.     /// // This test would fail if this is true: These should fail to compile but the above trait interferes and causes them to actually compile anyway.
  61.     /// assert_impl_any!((): From<u8>);
  62.     /// assert_impl_any!((): From<u8>, From<u16>);
  63.     /// ```
  64.     #[allow(dead_code)]
  65.     fn interference_for_fail_case() {}
  66.  
  67.     /// The macro isn't perfect and a trait with the correct method name can interfere with the macro.
  68.     ///
  69.     /// This tests the case with interference where the macro should normally succeed. The interference causes the macro to fail, this isn't really a problem since it is very unlikely that the correct trait actually exists.
  70.     ///
  71.     /// ```compile_fail
  72.     /// use playground::assert_impl_any;
  73.     ///
  74.     /// trait Interfere {
  75.     ///     #[allow(non_snake_case)]
  76.     ///     fn __static_assert__has_any_trait(&self: token: ()) {}
  77.     /// }
  78.     /// impl<T> Interfere for T {}
  79.     ///
  80.     /// // These should actually compile but the above trait interferes and causes them to fail anyway.
  81.     /// assert_impl_any!((): Send, Sync);
  82.     /// assert_impl_any!((): Send, From<u8>);
  83.     /// ```
  84.     #[allow(dead_code)]
  85.     fn interference_for_success_case() {}
  86.  
  87.     /// A function that should fail to compile.
  88.     ///
  89.     /// ```compile_fail
  90.     /// use playground::assert_impl_any;
  91.     /// assert_impl_any!((): From<u8>);
  92.     /// assert_impl_any!((): From<u8>, From<u16>);
  93.     /// ```
  94.     #[allow(dead_code)]
  95.     fn should_fail() {}
  96. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top