static_assertions/
assert_impl.rs

1/// Asserts that the type implements exactly one in a set of traits.
2///
3/// Related:
4/// - [`assert_impl_any!`]
5/// - [`assert_impl_all!`]
6/// - [`assert_not_impl_all!`]
7/// - [`assert_not_impl_any!`]
8///
9/// # Examples
10///
11/// Given some type `Foo`, it is expected to implement either `Snap`, `Crackle`,
12/// or `Pop`:
13///
14/// ```compile_fail
15/// # use static_assertions::assert_impl_one; fn main() {}
16/// struct Foo;
17///
18/// trait Snap {}
19/// trait Crackle {}
20/// trait Pop {}
21///
22/// assert_impl_one!(Foo: Snap, Crackle, Pop);
23/// ```
24///
25/// If _only_ `Crackle` is implemented, the assertion passes:
26///
27/// ```
28/// # use static_assertions::assert_impl_one; fn main() {}
29/// # struct Foo;
30/// # trait Snap {}
31/// # trait Crackle {}
32/// # trait Pop {}
33/// impl Crackle for Foo {}
34///
35/// assert_impl_one!(Foo: Snap, Crackle, Pop);
36/// ```
37///
38/// If `Snap` or `Pop` is _also_ implemented, the assertion fails:
39///
40/// ```compile_fail
41/// # use static_assertions::assert_impl_one; fn main() {}
42/// # struct Foo;
43/// # trait Snap {}
44/// # trait Crackle {}
45/// # trait Pop {}
46/// # impl Crackle for Foo {}
47/// impl Pop for Foo {}
48///
49/// assert_impl_one!(Foo: Snap, Crackle, Pop);
50/// ```
51///
52/// [`assert_impl_any!`]:     macro.assert_impl_any.html
53/// [`assert_impl_all!`]:     macro.assert_impl_all.html
54/// [`assert_not_impl_all!`]: macro.assert_not_impl_all.html
55/// [`assert_not_impl_any!`]: macro.assert_not_impl_any.html
56#[macro_export]
57macro_rules! assert_impl_one {
58    ($x:ty: $($t:path),+ $(,)?) => {
59        const _: fn() = || {
60            // Generic trait that must be implemented for `$x` exactly once.
61            trait AmbiguousIfMoreThanOne<A> {
62                // Required for actually being able to reference the trait.
63                fn some_item() {}
64            }
65
66            // Creates multiple scoped `Token` types for each trait `$t`, over
67            // which a specialized `AmbiguousIfMoreThanOne<Token>` is
68            // implemented for every type that implements `$t`.
69            $({
70                #[allow(dead_code)]
71                struct Token;
72
73                impl<T: ?Sized + $t> AmbiguousIfMoreThanOne<Token> for T {}
74            })+
75
76            // If there is only one specialized trait impl, type inference with
77            // `_` can be resolved and this can compile. Fails to compile if
78            // `$x` implements more than one `AmbiguousIfMoreThanOne<Token>` or
79            // does not implement any at all.
80            let _ = <$x as AmbiguousIfMoreThanOne<_>>::some_item;
81        };
82    };
83}
84
85/// Asserts that the type implements _all_ of the given traits.
86///
87/// See [`assert_not_impl_all!`] for achieving the opposite effect.
88///
89/// # Examples
90///
91/// This can be used to ensure types implement auto traits such as [`Send`] and
92/// [`Sync`], as well as traits with [blanket `impl`s][blanket].
93///
94/// ```
95/// # #[macro_use] extern crate static_assertions; fn main() {}
96/// assert_impl_all!(u32: Copy, Send);
97/// assert_impl_all!(&str: Into<String>);
98/// ```
99///
100/// The following example fails to compile because raw pointers do not implement
101/// [`Send`] since they cannot be moved between threads safely:
102///
103/// ```compile_fail
104/// # #[macro_use] extern crate static_assertions; fn main() {}
105/// assert_impl_all!(*const u8: Send);
106/// ```
107///
108/// [`assert_not_impl_all!`]: macro.assert_not_impl_all.html
109/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
110/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
111/// [blanket]: https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
112#[macro_export]
113macro_rules! assert_impl_all {
114    ($type:ty: $($trait:path),+ $(,)?) => {
115        const _: fn() = || {
116            // Only callable when `$type` implements all traits in `$($trait)+`.
117            fn assert_impl_all<T: ?Sized $(+ $trait)+>() {}
118            assert_impl_all::<$type>();
119        };
120    };
121}
122
123/// Asserts that the type implements _any_ of the given traits.
124///
125/// See [`assert_not_impl_any!`] for achieving the opposite effect.
126///
127/// # Examples
128///
129/// `u8` cannot be converted from `u16`, but it can be converted into `u16`:
130///
131/// ```
132/// # #[macro_use] extern crate static_assertions; fn main() {}
133/// assert_impl_any!(u8: From<u16>, Into<u16>);
134/// ```
135///
136/// The unit type cannot be converted from `u8` or `u16`, but it does implement
137/// [`Send`]:
138///
139/// ```
140/// # #[macro_use] extern crate static_assertions; fn main() {}
141/// assert_impl_any!((): From<u8>, From<u16>, Send);
142/// ```
143///
144/// The following example fails to compile because raw pointers do not implement
145/// [`Send`] or [`Sync`] since they cannot be moved or shared between threads
146/// safely:
147///
148/// ```compile_fail
149/// # #[macro_use] extern crate static_assertions; fn main() {}
150/// assert_impl_any!(*const u8: Send, Sync);
151/// ```
152///
153/// [`assert_not_impl_any!`]: macro.assert_not_impl_any.html
154/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
155/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
156#[macro_export]
157macro_rules! assert_impl_any {
158    ($x:ty: $($t:path),+ $(,)?) => {
159        const _: fn() = || {
160            use $crate::_core::marker::PhantomData;
161            use $crate::_core::ops::Deref;
162
163            // Fallback to use as the first iterative assignment to `previous`.
164            let previous = AssertImplAnyFallback;
165            struct AssertImplAnyFallback;
166
167            // Ensures that blanket traits can't impersonate the method. This
168            // prevents a false positive attack where---if a blanket trait is in
169            // scope that has `_static_assertions_impl_any`---the macro will
170            // compile when it shouldn't.
171            //
172            // See https://github.com/nvzqz/static-assertions-rs/issues/19 for
173            // more info.
174            struct ActualAssertImplAnyToken;
175            trait AssertImplAnyToken {}
176            impl AssertImplAnyToken for ActualAssertImplAnyToken {}
177            fn assert_impl_any_token<T: AssertImplAnyToken>(_: T) {}
178
179            $(let previous = {
180                struct Wrapper<T, N>(PhantomData<T>, N);
181
182                // If the method for this wrapper can't be called then the
183                // compiler will insert a deref and try again. This forwards the
184                // compiler's next attempt to the previous wrapper.
185                impl<T, N> Deref for Wrapper<T, N> {
186                    type Target = N;
187
188                    fn deref(&self) -> &Self::Target {
189                        &self.1
190                    }
191                }
192
193                // This impl is bounded on the `$t` trait, so the method can
194                // only be called if `$x` implements `$t`. This is why a new
195                // `Wrapper` is defined for each `previous`.
196                impl<T: $t, N> Wrapper<T, N> {
197                    fn _static_assertions_impl_any(&self) -> ActualAssertImplAnyToken {
198                        ActualAssertImplAnyToken
199                    }
200                }
201
202                Wrapper::<$x, _>(PhantomData, previous)
203            };)+
204
205            // Attempt to find the method that can actually be called. The found
206            // method must return a type that implements the sealed `Token`
207            // trait, this ensures that blanket trait methods can't cause this
208            // macro to compile.
209            assert_impl_any_token(previous._static_assertions_impl_any());
210        };
211    };
212}
213
214/// Asserts that the type does **not** implement _all_ of the given traits.
215///
216/// This can be used to ensure types do not implement auto traits such as
217/// [`Send`] and [`Sync`], as well as traits with [blanket `impl`s][blanket].
218///
219/// Note that the combination of all provided traits is required to not be
220/// implemented. If you want to check that none of multiple traits are
221/// implemented you should invoke [`assert_not_impl_any!`] instead.
222///
223/// # Examples
224///
225/// Although `u32` implements `From<u16>`, it does not implement `Into<usize>`:
226///
227/// ```
228/// # #[macro_use] extern crate static_assertions; fn main() {}
229/// assert_not_impl_all!(u32: From<u16>, Into<usize>);
230/// ```
231///
232/// The following example fails to compile since `u32` can be converted into
233/// `u64`.
234///
235/// ```compile_fail
236/// # #[macro_use] extern crate static_assertions; fn main() {}
237/// assert_not_impl_all!(u32: Into<u64>);
238/// ```
239///
240/// The following compiles because [`Cell`] is not both [`Sync`] _and_ [`Send`]:
241///
242/// ```
243/// # #[macro_use] extern crate static_assertions; fn main() {}
244/// use std::cell::Cell;
245///
246/// assert_not_impl_all!(Cell<u32>: Sync, Send);
247/// ```
248///
249/// But it is [`Send`], so this fails to compile:
250///
251/// ```compile_fail
252/// # #[macro_use] extern crate static_assertions; fn main() {}
253/// # std::cell::Cell;
254/// assert_not_impl_all!(Cell<u32>: Send);
255/// ```
256///
257/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
258/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
259/// [`assert_not_impl_any!`]: macro.assert_not_impl_any.html
260/// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html
261/// [blanket]: https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
262#[macro_export]
263macro_rules! assert_not_impl_all {
264    ($x:ty: $($t:path),+ $(,)?) => {
265        const _: fn() = || {
266            // Generic trait with a blanket impl over `()` for all types.
267            trait AmbiguousIfImpl<A> {
268                // Required for actually being able to reference the trait.
269                fn some_item() {}
270            }
271
272            impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
273
274            // Used for the specialized impl when *all* traits in
275            // `$($t)+` are implemented.
276            #[allow(dead_code)]
277            struct Invalid;
278
279            impl<T: ?Sized $(+ $t)+> AmbiguousIfImpl<Invalid> for T {}
280
281            // If there is only one specialized trait impl, type inference with
282            // `_` can be resolved and this can compile. Fails to compile if
283            // `$x` implements `AmbiguousIfImpl<Invalid>`.
284            let _ = <$x as AmbiguousIfImpl<_>>::some_item;
285        };
286    };
287}
288
289/// Asserts that the type does **not** implement _any_ of the given traits.
290///
291/// This can be used to ensure types do not implement auto traits such as
292/// [`Send`] and [`Sync`], as well as traits with [blanket `impl`s][blanket].
293///
294/// This macro causes a compilation failure if any of the provided individual
295/// traits are implemented for the type. If you want to check that a combination
296/// of traits is not implemented you should invoke [`assert_not_impl_all!`]
297/// instead. For single traits both macros behave the same.
298///
299/// # Examples
300///
301/// If `u32` were to implement `Into` conversions for `usize` _and_ for `u8`,
302/// the following would fail to compile:
303///
304/// ```
305/// # #[macro_use] extern crate static_assertions; fn main() {}
306/// assert_not_impl_any!(u32: Into<usize>, Into<u8>);
307/// ```
308///
309/// This is also good for simple one-off cases:
310///
311/// ```
312/// # #[macro_use] extern crate static_assertions; fn main() {}
313/// assert_not_impl_any!(&'static mut u8: Copy);
314/// ```
315///
316/// The following example fails to compile since `u32` can be converted into
317/// `u64` even though it can not be converted into a `u16`:
318///
319/// ```compile_fail
320/// # #[macro_use] extern crate static_assertions; fn main() {}
321/// assert_not_impl_any!(u32: Into<u64>, Into<u16>);
322/// ```
323///
324/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
325/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
326/// [`assert_not_impl_all!`]: macro.assert_not_impl_all.html
327/// [blanket]: https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
328#[macro_export]
329macro_rules! assert_not_impl_any {
330    ($x:ty: $($t:path),+ $(,)?) => {
331        const _: fn() = || {
332            // Generic trait with a blanket impl over `()` for all types.
333            trait AmbiguousIfImpl<A> {
334                // Required for actually being able to reference the trait.
335                fn some_item() {}
336            }
337
338            impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
339
340            // Creates multiple scoped `Invalid` types for each trait `$t`, over
341            // which a specialized `AmbiguousIfImpl<Invalid>` is implemented for
342            // every type that implements `$t`.
343            $({
344                #[allow(dead_code)]
345                struct Invalid;
346
347                impl<T: ?Sized + $t> AmbiguousIfImpl<Invalid> for T {}
348            })+
349
350            // If there is only one specialized trait impl, type inference with
351            // `_` can be resolved and this can compile. Fails to compile if
352            // `$x` implements any `AmbiguousIfImpl<Invalid>`.
353            let _ = <$x as AmbiguousIfImpl<_>>::some_item;
354        };
355    };
356}