Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #[macro_export]
- macro_rules! assert_impl_any {
- ($x:ty: $($t:path),+ $(,)?) => {
- const _: fn() = || {
- use core::marker::PhantomData;
- use core::ops::Deref;
- struct AssertAnyTraitNoTrait;
- let next = AssertAnyTraitNoTrait;
- // Ensures that blanket traits can't impersonate the method.
- struct AssertAnyTraitToken;
- $(
- let next = {
- struct Wrapper<T, N>(PhantomData<T>, N);
- // If the `__static_assert__has_any_trait` method for this wrapper can't be called then
- // the compiler will insert a deref and try again. This forwards the compilers next
- // attempt to the previous wrapper.
- impl<T, N> Deref for Wrapper<T, N> {
- type Target = N;
- fn deref(&self) -> &Self::Target {
- &self.1
- }
- }
- // This impl has a trait bound on $x so the method can only be called if $x implements $t.
- impl<T: $t, N> Wrapper<T, N> {
- #[allow(non_snake_case)]
- // The `TOKEN` generic ensures that a method on a blanket trait can't be generic and therefore accept the `AssertAnyTraitToken`.
- fn __static_assert__has_any_trait<TOKEN>(&self, _: AssertAnyTraitToken) {}
- }
- Wrapper::<$x, _>(PhantomData, next)
- };
- )+
- // Attempt to find a `__static_assert__has_any_trait` method that can actually be called.
- next.__static_assert__has_any_trait::<()>(AssertAnyTraitToken);
- };
- };
- }
- mod tests {
- #[test]
- fn should_compile() {
- assert_impl_any!((): Send, Sync);
- assert_impl_any!((): Send, From<u8>);
- assert_impl_any!((): From<u8>, From<u16>, Send);
- }
- /// The macro isn't perfect and a trait with the correct method name can interfere with the macro.
- ///
- /// 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.
- ///
- /// ```compile_fail
- /// use playground::assert_impl_any;
- ///
- /// trait Interfere {
- /// #[allow(non_snake_case)]
- /// fn __static_assert__has_any_trait<A>(&self, token: A) {}
- /// }
- /// impl<T> Interfere for T {}
- ///
- /// // 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.
- /// assert_impl_any!((): From<u8>);
- /// assert_impl_any!((): From<u8>, From<u16>);
- /// ```
- #[allow(dead_code)]
- fn interference_for_fail_case() {}
- /// The macro isn't perfect and a trait with the correct method name can interfere with the macro.
- ///
- /// 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.
- ///
- /// ```compile_fail
- /// use playground::assert_impl_any;
- ///
- /// trait Interfere {
- /// #[allow(non_snake_case)]
- /// fn __static_assert__has_any_trait(&self: token: ()) {}
- /// }
- /// impl<T> Interfere for T {}
- ///
- /// // These should actually compile but the above trait interferes and causes them to fail anyway.
- /// assert_impl_any!((): Send, Sync);
- /// assert_impl_any!((): Send, From<u8>);
- /// assert_impl_any!((): From<u8>, From<u16>, Send);
- /// ```
- #[allow(dead_code)]
- fn interference_for_success_case() {}
- /// A function that should fail to compile.
- ///
- /// ```compile_fail
- /// use playground::assert_impl_any;
- /// assert_impl_any!((): From<u8>);
- /// assert_impl_any!((): From<u8>, From<u16>);
- /// ```
- #[allow(dead_code)]
- fn should_fail() {}
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement