Skip to content

Commit d9f73f8

Browse files
authored
Merge pull request #17 from HeroicKatora/master
Add an assert_not_impl macro
2 parents eb442b6 + 261e73a commit d9f73f8

File tree

2 files changed

+214
-0
lines changed

2 files changed

+214
-0
lines changed

src/assert_not_impl.rs

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/// Asserts that the type does **not** implement all of the given traits.
2+
///
3+
/// This can be used to ensure types implement auto traits such as [`Send`] and
4+
/// [`Sync`], as well as traits with [blanket `impl`s][blanket].
5+
///
6+
/// Note that the combination of all provided traits is required to not be
7+
/// implemented. If you want to check that none of multiple traits are
8+
/// implemented you should invoke [`assert_not_impl_any`] instead.
9+
///
10+
/// # Examples
11+
///
12+
/// On stable Rust, using the macro requires a unique “label” when used in a
13+
/// module scope:
14+
///
15+
#[cfg_attr(feature = "nightly", doc = "```ignore")]
16+
#[cfg_attr(not(feature = "nightly"), doc = "```")]
17+
/// # #[macro_use] extern crate static_assertions;
18+
/// # use static_assertions::_core::cell::Cell;
19+
/// # fn main() {}
20+
/// assert_not_impl_all!(ptr0; *const u16, Send, Sync);
21+
/// assert_not_impl_all!(ptr1; *const u8, Send, Sync);
22+
/// ```
23+
///
24+
/// The [labeling limitation](index.html#limitations) is not necessary if
25+
/// compiling on nightly Rust with the `nightly` feature enabled:
26+
///
27+
#[cfg_attr(feature = "nightly", doc = "```")]
28+
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
29+
/// #![feature(underscore_const_names)]
30+
/// # #[macro_use] extern crate static_assertions;
31+
///
32+
/// assert_not_impl_all!(&'static mut u8, Copy);
33+
///
34+
/// fn main() {
35+
/// assert_not_impl_all!(u32, Into<usize>);
36+
/// }
37+
/// ```
38+
///
39+
/// The following example fails to compile since `u32` can be converted into
40+
/// `u64`.
41+
///
42+
/// ```compile_fail
43+
/// # #[macro_use] extern crate static_assertions;
44+
/// # fn main() {}
45+
/// assert_not_impl_all!(u32, Into<u64>);
46+
/// ```
47+
///
48+
/// `Cell<u32>` is not both `Sync` and `Send`.
49+
///
50+
#[cfg_attr(feature = "nightly", doc = "```ignore")]
51+
#[cfg_attr(not(feature = "nightly"), doc = "```")]
52+
/// # #[macro_use] extern crate static_assertions;
53+
/// # use static_assertions::_core::cell::Cell;
54+
/// # fn main() {}
55+
/// assert_not_impl_all!(cell; Cell<u32>, Sync, Send);
56+
/// ```
57+
/// But it is `Send`, so this fails to compile.
58+
///
59+
/// ```compile_fail
60+
/// # #[macro_use] extern crate static_assertions;
61+
/// # use static_assertions::_core::cell::Cell;
62+
/// # fn main() {}
63+
/// assert_not_impl_all!(cell; Cell<u32>, Send);
64+
/// ```
65+
///
66+
/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
67+
/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
68+
/// [`assert_not_impl_any`]: macro.assert_not_impl_any.html
69+
/// [blanket]: https://doc.rust-lang.org/book/second-edition/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
70+
#[macro_export(local_inner_macros)]
71+
macro_rules! assert_not_impl_all {
72+
($($xs:tt)+) => { _assert_not_impl_all!($($xs)+); };
73+
}
74+
75+
/// Asserts that the type does **not** implement any of the given traits.
76+
///
77+
/// This can be used to ensure types implement auto traits such as [`Send`] and
78+
/// [`Sync`], as well as traits with [blanket `impl`s][blanket].
79+
///
80+
/// The result of the macro fails to compile if any of the provided individual
81+
/// traits are implemented for the type. If you want to check that a combination
82+
/// of traits is not implemented you should invoke [`assert_not_impl_all`]
83+
/// instead. For single traits both macros behave the same.
84+
///
85+
/// # Examples
86+
///
87+
/// On stable Rust, using the macro requires a unique “label” when used in a
88+
/// module scope:
89+
///
90+
#[cfg_attr(feature = "nightly", doc = "```ignore")]
91+
#[cfg_attr(not(feature = "nightly"), doc = "```")]
92+
/// # #[macro_use] extern crate static_assertions;
93+
/// # fn main() {}
94+
/// assert_not_impl_any!(ptr0; *const u16, Send);
95+
/// assert_not_impl_any!(ptr1; *const u8, Send, Sync);
96+
/// ```
97+
///
98+
/// The [labeling limitation](index.html#limitations) is not necessary if
99+
/// compiling on nightly Rust with the `nightly` feature enabled:
100+
///
101+
#[cfg_attr(feature = "nightly", doc = "```")]
102+
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
103+
/// #![feature(underscore_const_names)]
104+
/// # #[macro_use] extern crate static_assertions;
105+
///
106+
/// assert_not_impl_any!(&'static mut u8, Copy);
107+
///
108+
/// fn main() {
109+
/// assert_not_impl_any!(u32, Into<usize>);
110+
/// }
111+
/// ```
112+
///
113+
/// The following example fails to compile since `u32` can be converted into
114+
/// `u64` even though it can not be converted into a `u16`.
115+
///
116+
/// ```compile_fail
117+
/// # #[macro_use] extern crate static_assertions;
118+
/// # fn main() {}
119+
/// assert_not_impl_any!(u32, Into<u64>, Into<u16>);
120+
/// ```
121+
///
122+
/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
123+
/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
124+
/// [`assert_not_impl_all`]: macro.assert_not_impl_all.html
125+
/// [blanket]: https://doc.rust-lang.org/book/second-edition/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
126+
#[macro_export(local_inner_macros)]
127+
macro_rules! assert_not_impl_any {
128+
($($xs:tt)+) => { _assert_not_impl_any!($($xs)+); };
129+
}
130+
131+
#[doc(hidden)]
132+
#[cfg(feature = "nightly")]
133+
#[macro_export(local_inner_macros)]
134+
macro_rules! _assert_not_impl_all {
135+
($x:ty, $($t:path),+ $(,)*) => {
136+
const _: fn() -> () = || {
137+
#[allow(dead_code)]
138+
struct Invalid;
139+
trait AmbiguousIfImpl<A> { fn some_item() {} }
140+
141+
impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
142+
impl<T: ?Sized $(+ $t)*> AmbiguousIfImpl<Invalid> for T {}
143+
144+
let _ = <$x as AmbiguousIfImpl<_>>::some_item;
145+
};
146+
};
147+
}
148+
149+
#[doc(hidden)]
150+
#[cfg(not(feature = "nightly"))]
151+
#[macro_export(local_inner_macros)]
152+
macro_rules! _assert_not_impl_all {
153+
($x:ty, $($t:path),+ $(,)*) => {
154+
{
155+
#[allow(dead_code)]
156+
struct Invalid;
157+
trait AmbiguousIfImpl<A> { fn some_item() {} }
158+
159+
impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
160+
impl<T: ?Sized $(+ $t)*> AmbiguousIfImpl<Invalid> for T {}
161+
162+
let _ = <$x as AmbiguousIfImpl<_>>::some_item;
163+
}
164+
};
165+
($label:ident; $($xs:tt)+) => {
166+
#[allow(dead_code, non_snake_case)]
167+
fn $label() { assert_not_impl_all!($($xs)+); }
168+
};
169+
}
170+
171+
#[doc(hidden)]
172+
#[cfg(feature = "nightly")]
173+
#[macro_export(local_inner_macros)]
174+
macro_rules! _assert_not_impl_any {
175+
($x:ty, $($t:path),+ $(,)*) => {
176+
const _: fn() -> () = || {
177+
trait AmbiguousIfImpl<A> { fn some_item() {} }
178+
179+
impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
180+
$({
181+
#[allow(dead_code)]
182+
struct Invalid;
183+
impl<T: ?Sized + $t> AmbiguousIfImpl<Invalid> for T {}
184+
})+
185+
186+
let _ = <$x as AmbiguousIfImpl<_>>::some_item;
187+
};
188+
};
189+
}
190+
191+
#[doc(hidden)]
192+
#[cfg(not(feature = "nightly"))]
193+
#[macro_export(local_inner_macros)]
194+
macro_rules! _assert_not_impl_any {
195+
($x:ty, $($t:path),+ $(,)*) => {
196+
{
197+
trait AmbiguousIfImpl<A> { fn some_item() {} }
198+
199+
impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
200+
$({
201+
#[allow(dead_code)]
202+
struct Invalid;
203+
impl<T: ?Sized + $t> AmbiguousIfImpl<Invalid> for T {}
204+
})+
205+
206+
let _ = <$x as AmbiguousIfImpl<_>>::some_item;
207+
}
208+
};
209+
($label:ident; $($xs:tt)+) => {
210+
#[allow(dead_code, non_snake_case)]
211+
fn $label() { assert_not_impl_any!($($xs)+); }
212+
};
213+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ mod assert_eq_size;
133133
mod assert_eq_type;
134134
mod assert_fields;
135135
mod assert_impl;
136+
mod assert_not_impl;
136137
mod assert_ne_type;
137138
mod assert_obj_safe;
138139
mod const_assert;

0 commit comments

Comments
 (0)