use std::{
ffi::c_void,
fmt::{Debug, Formatter, Result as FmtResult},
marker::PhantomData,
mem::MaybeUninit,
ptr::NonNull,
};
use jl_sys::jl_bottom_type;
use super::valid_layout::{ValidField, ValidLayout};
use crate::{
data::{
managed::{
Managed, datatype::DataType, private::ManagedPriv as _, union::Union, value::Value,
},
types::{construct_type::ConstructType, typecheck::Typecheck},
},
prelude::LocalScope,
private::Private,
weak_handle,
};
#[repr(C, align(1))]
#[derive(Copy, Clone, PartialEq)]
pub struct Align1;
unsafe impl Align for Align1 {
const ALIGNMENT: usize = 1;
}
impl Debug for Align1 {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.write_str("Align<1 byte>")
}
}
#[repr(C, align(2))]
#[derive(Copy, Clone, PartialEq)]
pub struct Align2;
unsafe impl Align for Align2 {
const ALIGNMENT: usize = 2;
}
impl Debug for Align2 {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.write_str("Align<2 bytes>")
}
}
#[repr(C, align(4))]
#[derive(Copy, Clone, PartialEq)]
pub struct Align4;
unsafe impl Align for Align4 {
const ALIGNMENT: usize = 4;
}
impl Debug for Align4 {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.write_str("Align<4 bytes>")
}
}
#[repr(C, align(8))]
#[derive(Copy, Clone, PartialEq)]
pub struct Align8;
unsafe impl Align for Align8 {
const ALIGNMENT: usize = 8;
}
impl Debug for Align8 {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.write_str("Align<8 bytes>")
}
}
#[repr(C, align(16))]
#[derive(Copy, Clone, PartialEq)]
pub struct Align16;
unsafe impl Align for Align16 {
const ALIGNMENT: usize = 16;
}
impl Debug for Align16 {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.write_str("Align<16 bytes>")
}
}
#[derive(Copy, Clone)]
pub struct BitsUnion<const N: usize>([MaybeUninit<u8>; N]);
impl<const N: usize> Debug for BitsUnion<N> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.write_fmt(format_args!("BitsUnion<{}>", N))
}
}
unsafe impl<const N: usize> BitsUnionContainer for BitsUnion<N> {
fn check_union_type(_: Union) -> bool {
true
}
}
pub struct TypedBitsUnion<U, const N: usize>(BitsUnion<N>, PhantomData<U>);
impl<T: ConstructType, const N: usize> Debug for TypedBitsUnion<T, N> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.write_fmt(format_args!("TypedBitsUnion<{}>", N))
}
}
impl<U, const N: usize> Clone for TypedBitsUnion<U, N> {
fn clone(&self) -> Self {
Self(self.0, PhantomData)
}
}
impl<U, const N: usize> Copy for TypedBitsUnion<U, N> {}
unsafe impl<T: ConstructType, const N: usize> BitsUnionContainer for TypedBitsUnion<T, N> {
fn check_union_type(u: Union) -> bool {
match weak_handle!() {
Ok(handle) => {
handle.local_scope::<_, 1>(|mut frame| T::construct_type(&mut frame) == u)
}
Err(_e) => {
panic!("TypedBitsUnion::check_union_type called outside julia context")
}
}
}
}
#[doc(hidden)]
pub unsafe fn correct_layout_for<A: Align, B: BitsUnionContainer, F: Flag>(u: Union) -> bool {
let mut bu_sz = 0;
let mut bu_align = 0;
if !B::check_union_type(u) {
return false;
}
if !u.isbits_size_align(&mut bu_sz, &mut bu_align) {
return false;
}
A::ALIGNMENT == bu_align && std::mem::size_of::<B>() == bu_sz
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct EmptyUnion(MaybeUninit<*mut c_void>);
impl Debug for EmptyUnion {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.write_str("Union{}")
}
}
unsafe impl ValidLayout for EmptyUnion {
#[inline]
fn valid_layout(ty: Value) -> bool {
unsafe { ty.unwrap(Private) == jl_bottom_type }
}
const IS_REF: bool = true;
fn type_object<'target, Tgt: crate::prelude::Target<'target>>(
_target: &Tgt,
) -> Value<'target, 'static> {
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_bottom_type), Private) }
}
}
unsafe impl ValidField for EmptyUnion {
#[inline]
fn valid_field(ty: Value) -> bool {
unsafe { ty.unwrap(Private) == jl_bottom_type }
}
}
unsafe impl Typecheck for EmptyUnion {
#[inline]
fn typecheck(t: DataType) -> bool {
<Self as ValidLayout>::valid_layout(t.as_value())
}
}
pub unsafe trait Align: private::AlignPriv {
const ALIGNMENT: usize;
}
pub unsafe trait BitsUnionContainer: private::BitsUnionContainerPriv {
fn check_union_type(u: Union) -> bool;
}
pub unsafe trait Flag: private::FlagPriv {}
unsafe impl Flag for u8 {}
mod private {
use std::fmt::Debug;
use super::{Align1, Align2, Align4, Align8, Align16, BitsUnion, TypedBitsUnion};
use crate::data::types::construct_type::ConstructType;
pub trait AlignPriv: Copy + Debug {}
impl AlignPriv for Align1 {}
impl AlignPriv for Align2 {}
impl AlignPriv for Align4 {}
impl AlignPriv for Align8 {}
impl AlignPriv for Align16 {}
pub trait BitsUnionContainerPriv: Copy + Debug {}
impl<const N: usize> BitsUnionContainerPriv for BitsUnion<N> {}
impl<T: ConstructType, const N: usize> BitsUnionContainerPriv for TypedBitsUnion<T, N> {}
pub trait FlagPriv: Copy + Debug {}
impl FlagPriv for u8 {}
}