Closed michaelsproul closed 2 years ago
Having played with this some more I think we can make a single generic macro by passing in the constructor :heart_eyes:
#[macro_export]
macro_rules! map_beacon_block {
($block:expr, $e:expr) => {
match $block {
BeaconBlock::Base(inner) => {
let f: fn(
BeaconBlockBase<_, _>,
fn(BeaconBlockBase<_, _>) -> BeaconBlock<_, _>,
) -> _ = $e;
f(inner, BeaconBlock::Base)
}
BeaconBlock::Altair(inner) => {
let f: fn(
BeaconBlockAltair<_, _>,
fn(BeaconBlockAltair<_, _>) -> BeaconBlock<_, _>,
) -> _ = $e;
f(inner, BeaconBlock::Altair)
}
BeaconBlock::Merge(inner) => {
let f: fn(
BeaconBlockMerge<_, _>,
fn(BeaconBlockMerge<_, _>) -> BeaconBlock<_, _>,
) -> _ = $e;
f(inner, BeaconBlock::Merge)
}
}
};
}
Then at the use site the caller can choose to ignore or use the variant constructor as they wish:
fn from(block: BeaconBlock<E, FullPayload<E>>) -> Self {
map_beacon_block!(block, |inner, cons| {
let (block, payload) = inner.into();
(cons(block), payload)
})
}
Love it!
I've just implemented this pattern by hand, which comes up a lot when using
superstruct
:I think we could generate the
map_beacon_block_variants
macro using superstruct, and maybe some other macros with a similar structure, like mapping into a common type rather thanSelf
.