use std::any;
use std::mem;
use crate::eval::bc::instr::BcInstr;
use crate::eval::bc::opcode::BcOpcode;
use crate::eval::bc::opcode::BcOpcodeHandler;
pub(crate) const BC_INSTR_ALIGN: usize = 8;
#[derive(Clone, Copy)]
#[repr(C)]
pub(crate) struct BcInstrHeader {
pub(crate) opcode: BcOpcode,
}
impl BcInstrHeader {
fn for_instr<I: BcInstr>() -> BcInstrHeader {
Self {
opcode: BcOpcode::for_instr::<I>(),
}
}
pub(crate) const fn for_opcode(opcode: BcOpcode) -> Self {
Self { opcode }
}
}
#[repr(C, align(8))]
pub(crate) struct BcInstrRepr<I: BcInstr> {
pub(crate) header: BcInstrHeader,
pub(crate) arg: I::Arg,
pub(crate) _align: [u64; 0],
}
impl<I: BcInstr> BcInstrRepr<I> {
pub(crate) fn new(arg: I::Arg) -> BcInstrRepr<I> {
BcInstrRepr::<I>::assert_align();
BcInstrRepr {
header: BcInstrHeader::for_instr::<I>(),
arg,
_align: [],
}
}
pub(crate) fn assert_align() {
assert!(
mem::align_of::<BcInstrRepr<I>>() == BC_INSTR_ALIGN,
"align: {}, required align: {}, type: {}",
mem::align_of::<BcInstrRepr<I>>(),
BC_INSTR_ALIGN,
any::type_name::<BcInstrRepr<I>>()
);
assert!(
mem::size_of::<BcInstrRepr<I>>() % BC_INSTR_ALIGN == 0,
"{}",
any::type_name::<BcInstrRepr<I>>()
);
}
}
impl BcOpcode {
pub(crate) fn size_of_repr(self) -> usize {
struct HandlerImpl;
impl BcOpcodeHandler<usize> for HandlerImpl {
fn handle<I: BcInstr>(self) -> usize {
<BcInstrRepr<I>>::assert_align();
mem::size_of::<BcInstrRepr<I>>()
}
}
self.dispatch(HandlerImpl)
}
}