Created
April 27, 2022 21:28
-
-
Save voronaam/537a7b15078a4f33187e91d70fa7bb25 to your computer and use it in GitHub Desktop.
Poor man's specialization in Rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
macro_rules! assert_impls {( | |
#[rustc_on_unimplemented(message = $message:expr $(,)?)] | |
$T:ty : $($trait:tt)+ | |
) => (const _: () = { | |
#[allow(unused)] | |
use __poormans_specialization::Fallback as _; | |
mod __poormans_specialization { | |
pub(super) | |
struct Wrapper<T : ?::core::marker::Sized>(T); | |
pub(super) | |
trait Fallback { | |
const __DOES_IMPL: bool = false; | |
} | |
impl<T : ?::core::marker::Sized> Fallback for Wrapper<T> {} | |
} | |
impl<__T : ?::core::marker::Sized> __poormans_specialization::Wrapper<__T> | |
where | |
__T : $($trait)+ | |
{ | |
const __DOES_IMPL: bool = true; | |
} | |
/// Simply `const`-panicking may be delayed to after trait-checking | |
/// thus missing the error message. | |
/// We thus need to force an eager evaluation of the constant. | |
const __EAGER: ::core::primitive::bool = { | |
if ! __poormans_specialization::Wrapper::<$T>::__DOES_IMPL { | |
::core::panic!(::core::concat!( | |
"\n = note: ", | |
$message, | |
)); | |
} | |
const _: [(); __EAGER as ::core::primitive::usize] = []; | |
false | |
}; | |
};)} | |
trait MyImportantTrait<T> {} | |
trait ImplExistCheck<T> | |
where | |
Self : MyImportantTrait<T>, | |
{} | |
macro_rules! first {( | |
$s:ident for $t:ty $(,)? | |
) => ( | |
assert_impls! { | |
#[rustc_on_unimplemented( | |
message = ::core::concat!( | |
"you may want to call `second!(", | |
stringify!($s), | |
" for ", | |
stringify!($t), | |
")`", | |
), | |
)] | |
$s : MyImportantTrait<$t> | |
} | |
impl ImplExistCheck<$t> for $s {} | |
)} | |
macro_rules! second {( | |
$s:ident for $t:ty $(,)? | |
) => ( | |
impl MyImportantTrait<$t> for $s {} | |
)} | |
struct A {} | |
first!(A for u64); | |
second!(A for u16); // Note the intentional wrong type (a mistake) | |
fn main () | |
{} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment