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