use core::mem::MaybeUninit;
use crate::Const;
use generic_upper_bound as gub;
mod gen {
include!(concat!(env!("OUT_DIR"), "/for_each_align.rs"));
pub(crate) use for_each_align;
}
pub(crate) use gen::for_each_align;
pub const unsafe fn promote<'a, C: Const>() -> &'a C::Type {
unsafe { &*core::ptr::from_ref(gub::eval_with_upper_bound::<Promote<C>>()).cast() }
}
trait Anything {}
impl<T> Anything for T {}
struct Promote<C>(C);
impl<C: Const> gub::AcceptUpperBound for Promote<C> {
type Output = &'static dyn Anything;
const DESIRED_GENERIC: usize = size_of::<C::Type>();
type Eval<const UPPER: usize> = PromoteSized<C, UPPER>;
}
#[repr(C)]
struct AlignedBuf<Aligner, const SIZE: usize>([MaybeUninit<u8>; SIZE], Aligner);
struct PromoteSized<C, const SIZE: usize>(C);
impl<C: Const, const SIZE: usize> Const for PromoteSized<C, SIZE> {
type Type = &'static dyn Anything;
const VALUE: Self::Type = if gub::get_upper_bound::<Promote<C>>() == SIZE {
const fn const_to_buf<C: Const, const SIZE: usize>() -> [MaybeUninit<u8>; SIZE] {
use core::mem::ManuallyDrop;
#[repr(C)]
union Transmute<T, const SIZE: usize> {
val: ManuallyDrop<T>,
buf: [MaybeUninit<u8>; SIZE],
}
unsafe {
Transmute {
val: ManuallyDrop::new(crate::value_of::<C>()),
}
.buf
}
}
macro_rules! handle_aligns {
($($align:literal)*) => {
$(if align_of::<C::Type>() == $align {
#[repr(align($align))]
struct Aligner;
&AlignedBuf(const_to_buf::<C, SIZE>(), Aligner)
} else )* {
panic!("Unknown alignment")
}
};
}
for_each_align!(handle_aligns)
} else {
&()
};
}
#[test]
fn promote_adt() {
#[repr(align(256))]
#[derive(PartialEq, Eq, Debug)]
struct Inner([u32; 3]);
#[repr(C)]
#[derive(PartialEq, Eq, Debug)]
struct Composite {
f: Option<[fn() -> i32; 3]>,
a: Inner,
r: &'static u32,
p: *const u32,
b: bool,
}
fn f<const N: i32>() -> i32 {
N
}
struct Value;
impl Const for Value {
type Type = Composite;
const VALUE: Self::Type = Composite {
f: Some([f::<1>, f::<420>, f::<13>]),
a: Inner([3, 2, 1]),
r: &1,
p: std::ptr::without_provenance(42),
b: true,
};
}
let promoted = unsafe { promote::<Value>() };
assert_eq!(&Value::VALUE, promoted);
}