Make assert_impl_one! work with all combinations

Fixes the issue where subsequent traits were only checked against the
first trait and not to one another. This solution was made possible by
@SimonSapin demonstrating to me how to expand the input sequence into
combinations of inputs.

Closes #20.
This commit is contained in:
Nikolai Vazquez 2019-10-18 13:29:04 -04:00
parent f096b6dcab
commit ea9ec5dd9f
2 changed files with 26 additions and 3 deletions

View File

@ -52,10 +52,16 @@
macro_rules! assert_impl_one {
($type:ty: $t:path, $($ts:path),+ $(,)?) => {
assert_impl_any!($type: $t, $($ts),+);
// FIXME: Only works against the first trait; needs to check all
// subsequent traits against one another.
$(assert_not_impl_all!($type: $t, $ts);)+
assert_impl_one!(_priv $type: $t, $($ts),+);
};
// Expands into all combinations of trait pairs to ensure `$type` does not
// implement any pair of traits.
(_priv $type:ty: $t:path, $($ts:path),+) => {
$(assert_not_impl_all!($type: $t, $ts);)+
assert_impl_one!(_priv $type: $($ts),+);
};
// Finished passing along pairs, nothing to do.
(_priv $type:ty: $t:path) => {};
}
/// Asserts that the type implements _all_ of the given traits.

View File

@ -20,3 +20,20 @@ assert_impl_all!(str: Send, Sync, AsRef<[u8]>,);
assert_impl_any!((): Send, Sync);
assert_impl_any!((): Send, From<u8>);
assert_impl_any!((): From<u8>, From<u16>, Send);
#[allow(dead_code)]
struct Foo;
trait A {}
trait B {}
trait C {}
impl B for Foo {}
assert_impl_one!(Foo: A, B);
assert_impl_one!(Foo: B, A);
assert_impl_one!(Foo: B, C);
assert_impl_one!(Foo: C, B);
assert_impl_one!(Foo: A, B, C);
assert_impl_one!(Foo: B, C, A);
assert_impl_one!(Foo: C, A, B);