• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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]
57 macro_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]
113 macro_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]
157 macro_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]
263 macro_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]
329 macro_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 }
357