Skip to content

Instantly share code, notes, and snippets.

@voronaam
Created April 27, 2022 21:28
Show Gist options
  • Save voronaam/537a7b15078a4f33187e91d70fa7bb25 to your computer and use it in GitHub Desktop.
Save voronaam/537a7b15078a4f33187e91d70fa7bb25 to your computer and use it in GitHub Desktop.
Poor man's specialization in Rust
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