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