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
/// Asserts that the traits are [object-safe][object].
///
/// This is useful for when changes are made to a trait that accidentally
/// prevent it from being used as an [object]. Such a case would be adding a
/// generic method and forgetting to add `where Self: Sized` after it. If left
/// unnoticed, that mistake will affect crate users and break both forward and
/// backward compatibility.
///
/// # Examples
///
/// When exposing a public API, it's important that traits that could previously
/// use dynamic dispatch can still do so in future compatible crate versions.
///
#[cfg_attr(feature = "nightly", doc = "```ignore")]
#[cfg_attr(not(feature = "nightly"), doc = "```")]
/// # #[macro_use] extern crate static_assertions;
/// // Requires a unique label in module scope
/// assert_obj_safe!(basic; Send, Sync, AsRef<str>);
///
/// mod inner {
/// // Works with traits that are not in the calling module
/// pub trait BasicTrait {
/// fn foo(&self);
/// }
/// }
///
/// trait MySafeTrait {
/// fn bar(&self) -> u32;
/// }
///
/// fn main() {
/// assert_obj_safe!(MySafeTrait);
/// assert_obj_safe!(inner::BasicTrait);
/// }
/// ```
///
/// The [labeling limitation](index.html#limitations) is not necessary if
/// compiling on nightly Rust with the `nightly` feature enabled:
///
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
/// #![feature(underscore_const_names)]
/// # #[macro_use] extern crate static_assertions;
///
/// use std::fmt;
///
/// assert_obj_safe!(fmt::Write);
///
/// fn main() {
/// assert_obj_safe!(fmt::Debug);
/// }
/// ```
///
/// Raw pointers cannot be sent between threads safely:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {
/// assert_impl!(*const u8, Send);
/// # }
/// ```
///
/// Generics without `where Self: Sized` are not allowed in
/// [object-safe][object] trait methods:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// trait MyUnsafeTrait {
/// fn baz<T>(&self) -> T;
/// }
///
/// # fn main() {
/// assert_obj_safe!(MyUnsafeTrait);
/// # }
/// ```
///
/// [object]: https://doc.rust-lang.org/book/2018-edition/ch17-02-trait-objects.html#object-safety-is-required-for-trait-objects
#[macro_export(local_inner_macros)]
macro_rules! assert_obj_safe {
($($xs:tt)+) => { _assert_obj_safe!($($xs)+); };
}
#[doc(hidden)]
#[cfg(feature = "nightly")]
#[macro_export(local_inner_macros)]
macro_rules! _assert_obj_safe {
($($xs:ty),+ $(,)*) => {
$(const _: Option<&$xs> = None;)+
};
}
#[doc(hidden)]
#[cfg(not(feature = "nightly"))]
#[macro_export(local_inner_macros)]
macro_rules! _assert_obj_safe {
($($xs:ty),+ $(,)*) => {
$(let _: &$xs;)+
};
($label:ident; $($xs:tt)+) => {
#[allow(dead_code, non_snake_case)]
fn $label() { assert_obj_safe!($($xs)+); }
};
}