use crate::error::{JlrsError, JlrsResult};
use crate::frame::Output;
use crate::global::Global;
use crate::traits::{private::Internal, Cast, Frame, JuliaTypecheck};
use crate::value::symbol::Symbol;
use crate::value::type_name::TypeName;
use crate::value::Value;
use crate::{impl_julia_type, impl_julia_typecheck, impl_valid_layout};
use jl_sys::{
jl_abstractslot_type, jl_abstractstring_type, jl_any_type, jl_anytuple_type,
jl_argumenterror_type, jl_bool_type, jl_boundserror_type, jl_builtin_type, jl_char_type,
jl_code_info_type, jl_code_instance_type, jl_datatype_align, jl_datatype_isinlinealloc,
jl_datatype_nbits, jl_datatype_nfields, jl_datatype_size, jl_datatype_t, jl_datatype_type,
jl_emptytuple_type, jl_errorexception_type, jl_expr_type, jl_field_isptr, jl_field_names,
jl_field_offset, jl_field_size, jl_float16_type, jl_float32_type, jl_float64_type,
jl_floatingpoint_type, jl_function_type, jl_get_fieldtypes, jl_globalref_type,
jl_gotonode_type, jl_initerror_type, jl_int16_type, jl_int32_type, jl_int64_type, jl_int8_type,
jl_intrinsic_type, jl_is_cpointer_type, jl_isbits, jl_lineinfonode_type,
jl_linenumbernode_type, jl_loaderror_type, jl_method_instance_type, jl_method_type,
jl_methoderror_type, jl_methtable_type, jl_module_type, jl_namedtuple_typename, jl_new_structv,
jl_newvarnode_type, jl_nothing_type, jl_number_type, jl_phicnode_type, jl_phinode_type,
jl_pinode_type, jl_quotenode_type, jl_signed_type, jl_simplevector_type, jl_slotnumber_type,
jl_ssavalue_type, jl_string_type, jl_svec_data, jl_svec_len, jl_symbol_type, jl_task_type,
jl_tvar_type, jl_typedslot_type, jl_typeerror_type, jl_typemap_entry_type,
jl_typemap_level_type, jl_typename_str, jl_typename_type, jl_typeofbottom_type, jl_uint16_type,
jl_uint32_type, jl_uint64_type, jl_uint8_type, jl_undefvarerror_type, jl_unionall_type,
jl_uniontype_type, jl_upsilonnode_type, jl_voidpointer_type, jl_weakref_type,
};
use std::ffi::CStr;
use std::fmt::{Debug, Formatter, Result as FmtResult};
use std::marker::PhantomData;
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
#[repr(transparent)]
pub struct DataType<'frame>(*mut jl_datatype_t, PhantomData<&'frame ()>);
impl<'frame> DataType<'frame> {
pub(crate) unsafe fn wrap(datatype: *mut jl_datatype_t) -> Self {
DataType(datatype, PhantomData)
}
#[doc(hidden)]
pub unsafe fn ptr(self) -> *mut jl_datatype_t {
self.0
}
pub fn is<T: JuliaTypecheck>(self) -> bool {
unsafe { T::julia_typecheck(self) }
}
pub fn size(self) -> i32 {
unsafe { jl_datatype_size(self.0) }
}
pub fn align(self) -> u16 {
unsafe { jl_datatype_align(self.0) }
}
pub fn nbits(self) -> i32 {
unsafe { jl_datatype_nbits(self.0) }
}
pub fn nfields(self) -> u32 {
unsafe { jl_datatype_nfields(self.0) }
}
pub fn isinlinealloc(self) -> bool {
unsafe { jl_datatype_isinlinealloc(self.0) != 0 }
}
pub fn name(self) -> &'frame str {
unsafe {
let name = jl_typename_str(self.ptr().cast());
CStr::from_ptr(name).to_str().unwrap()
}
}
pub fn type_name(self) -> TypeName<'frame> {
unsafe { TypeName::wrap((&*self.ptr()).name) }
}
pub fn field_names(self) -> &'frame [Symbol<'frame>] {
unsafe {
let field_names = jl_field_names(self.ptr().cast());
let len = jl_svec_len(field_names);
let items = jl_svec_data(field_names);
std::slice::from_raw_parts(items.cast(), len)
}
}
pub fn field_types(self) -> &'frame [Value<'frame, 'static>] {
unsafe {
let field_types = jl_get_fieldtypes(self.ptr());
let len = jl_svec_len(field_types);
let items = jl_svec_data(field_types);
std::slice::from_raw_parts(items.cast(), len)
}
}
pub fn field_size(self, idx: usize) -> u32 {
unsafe { jl_field_size(self.ptr(), idx as _) }
}
pub fn field_offset(self, idx: usize) -> u32 {
unsafe { jl_field_offset(self.ptr(), idx as _) }
}
pub fn is_pointer_field(self, idx: usize) -> bool {
unsafe { jl_field_isptr(self.ptr(), idx as _) }
}
pub fn isbits(self) -> bool {
unsafe { jl_isbits(self.ptr().cast()) }
}
pub fn super_type(self) -> Option<Self> {
unsafe {
let sup = (&*self.ptr()).super_;
if sup.is_null() {
None
} else {
Some(DataType::wrap(sup))
}
}
}
pub fn parameters(self) -> &'frame [Value<'frame, 'static>] {
unsafe {
let params = (&*self.ptr()).parameters;
std::slice::from_raw_parts(jl_svec_data(params).cast(), jl_svec_len(params))
}
}
pub fn instance(self) -> Option<Value<'frame, 'static>> {
unsafe {
let instance = (&*self.ptr()).instance;
if instance.is_null() {
None
} else {
Some(Value::wrap(instance))
}
}
}
pub fn n_initialized(self) -> i32 {
unsafe { (&*self.ptr()).ninitialized }
}
pub fn hash(self) -> u32 {
unsafe { (&*self.ptr()).hash }
}
pub fn is_abstract(self) -> bool {
unsafe { (&*self.ptr()).abstract_ != 0 }
}
pub fn mutable(self) -> bool {
unsafe { (&*self.ptr()).mutabl != 0 }
}
pub fn has_free_type_vars(self) -> bool {
unsafe { (&*self.ptr()).hasfreetypevars != 0 }
}
pub fn is_concrete_type(self) -> bool {
unsafe { (&*self.ptr()).isconcretetype != 0 }
}
pub fn is_dispatch_tuple(self) -> bool {
unsafe { (&*self.ptr()).isdispatchtuple != 0 }
}
pub fn zeroinit(self) -> bool {
unsafe { (&*self.ptr()).zeroinit != 0 }
}
pub fn has_concrete_subtype(self) -> bool {
unsafe { (&*self.ptr()).has_concrete_subtype != 0 }
}
pub fn as_value(self) -> Value<'frame, 'static> {
self.into()
}
pub fn instantiate<'fr, 'value, 'borrow, F, V>(
self,
frame: &mut F,
mut values: V,
) -> JlrsResult<Value<'fr, 'borrow>>
where
F: Frame<'fr>,
V: AsMut<[Value<'value, 'borrow>]>,
{
unsafe {
if !self.is::<Concrete>() {
Err(JlrsError::NotConcrete(self.name().into()))?;
}
let values = values.as_mut();
let value = jl_new_structv(self.ptr(), values.as_mut_ptr().cast(), values.len() as _);
frame.protect(value, Internal).map_err(Into::into)
}
}
pub fn instantiate_output<'output, 'fr, 'value, 'borrow, F, V>(
self,
frame: &mut F,
output: Output<'output>,
values: V,
) -> JlrsResult<Value<'output, 'borrow>>
where
F: Frame<'fr>,
V: AsMut<[Value<'value, 'borrow>]>,
{
Value::instantiate_output(frame, output, self, values)
}
}
impl<'base> DataType<'base> {
pub fn typeofbottom_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_typeofbottom_type) }
}
pub fn datatype_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_datatype_type) }
}
pub fn uniontype_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_uniontype_type) }
}
pub fn unionall_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_unionall_type) }
}
pub fn tvar_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_tvar_type) }
}
pub fn any_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_any_type) }
}
pub fn typename_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_typename_type) }
}
pub fn symbol_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_symbol_type) }
}
pub fn ssavalue_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_ssavalue_type) }
}
pub fn abstractslot_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_abstractslot_type) }
}
pub fn slotnumber_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_slotnumber_type) }
}
pub fn typedslot_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_typedslot_type) }
}
pub fn simplevector_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_simplevector_type) }
}
pub fn anytuple_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_anytuple_type) }
}
pub fn tuple_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_anytuple_type) }
}
pub fn emptytuple_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_emptytuple_type) }
}
pub fn function_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_function_type) }
}
pub fn builtin_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_builtin_type) }
}
pub fn method_instance_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_method_instance_type) }
}
pub fn code_instance_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_code_instance_type) }
}
pub fn code_info_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_code_info_type) }
}
pub fn method_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_method_type) }
}
pub fn module_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_module_type) }
}
pub fn weakref_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_weakref_type) }
}
pub fn abstractstring_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_abstractstring_type) }
}
pub fn string_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_string_type) }
}
pub fn errorexception_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_errorexception_type) }
}
pub fn argumenterror_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_argumenterror_type) }
}
pub fn loaderror_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_loaderror_type) }
}
pub fn initerror_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_initerror_type) }
}
pub fn typeerror_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_typeerror_type) }
}
pub fn methoderror_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_methoderror_type) }
}
pub fn undefvarerror_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_undefvarerror_type) }
}
pub fn lineinfonode_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_lineinfonode_type) }
}
pub fn boundserror_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_boundserror_type) }
}
pub fn bool_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_bool_type) }
}
pub fn char_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_char_type) }
}
pub fn int8_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_int8_type) }
}
pub fn uint8_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_uint8_type) }
}
pub fn int16_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_int16_type) }
}
pub fn uint16_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_uint16_type) }
}
pub fn int32_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_int32_type) }
}
pub fn uint32_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_uint32_type) }
}
pub fn int64_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_int64_type) }
}
pub fn uint64_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_uint64_type) }
}
pub fn float16_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_float16_type) }
}
pub fn float32_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_float32_type) }
}
pub fn float64_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_float64_type) }
}
pub fn floatingpoint_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_floatingpoint_type) }
}
pub fn number_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_number_type) }
}
pub fn nothing_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_nothing_type) }
}
pub fn signed_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_signed_type) }
}
pub fn voidpointer_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_voidpointer_type) }
}
pub fn task_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_task_type) }
}
pub fn expr_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_expr_type) }
}
pub fn globalref_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_globalref_type) }
}
pub fn linenumbernode_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_linenumbernode_type) }
}
pub fn gotonode_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_gotonode_type) }
}
pub fn phinode_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_phinode_type) }
}
pub fn pinode_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_pinode_type) }
}
pub fn phicnode_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_phicnode_type) }
}
pub fn upsilonnode_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_upsilonnode_type) }
}
pub fn quotenode_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_quotenode_type) }
}
pub fn newvarnode_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_newvarnode_type) }
}
pub fn intrinsic_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_intrinsic_type) }
}
pub fn methtable_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_methtable_type) }
}
pub fn typemap_level_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_typemap_level_type) }
}
pub fn typemap_entry_type(_: Global<'base>) -> Self {
unsafe { Self::wrap(jl_typemap_entry_type) }
}
}
impl<'frame> Into<Value<'frame, 'static>> for DataType<'frame> {
fn into(self) -> Value<'frame, 'static> {
unsafe { Value::wrap(self.ptr().cast()) }
}
}
impl<'frame, 'data> Debug for DataType<'frame> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.debug_tuple("DataType").field(&self.name()).finish()
}
}
unsafe impl<'frame, 'data> Cast<'frame, 'data> for DataType<'frame> {
type Output = Self;
fn cast(value: Value<'frame, 'data>) -> JlrsResult<Self::Output> {
if value.is::<Self::Output>() {
return unsafe { Ok(Self::cast_unchecked(value)) };
}
Err(JlrsError::NotADataType)?
}
unsafe fn cast_unchecked(value: Value<'frame, 'data>) -> Self::Output {
DataType::wrap(value.ptr().cast())
}
}
impl_julia_type!(DataType<'frame>, jl_datatype_type, 'frame);
impl_valid_layout!(DataType<'frame>, 'frame);
pub struct Any;
impl_julia_typecheck!(Any, jl_any_type);
pub struct NamedTuple;
unsafe impl JuliaTypecheck for NamedTuple {
unsafe fn julia_typecheck(t: DataType) -> bool {
(&*t.ptr()).name == jl_namedtuple_typename
}
}
impl_julia_typecheck!(DataType<'frame>, jl_datatype_type, 'frame);
pub struct Mutable;
unsafe impl JuliaTypecheck for Mutable {
unsafe fn julia_typecheck(t: DataType) -> bool {
(&*t.ptr()).mutabl != 0
}
}
pub struct MutableDatatype;
unsafe impl JuliaTypecheck for MutableDatatype {
unsafe fn julia_typecheck(t: DataType) -> bool {
DataType::julia_typecheck(t) && (&*t.ptr()).mutabl != 0
}
}
pub struct Immutable;
unsafe impl JuliaTypecheck for Immutable {
unsafe fn julia_typecheck(t: DataType) -> bool {
(&*t.ptr()).mutabl == 0
}
}
pub struct ImmutableDatatype;
unsafe impl JuliaTypecheck for ImmutableDatatype {
unsafe fn julia_typecheck(t: DataType) -> bool {
DataType::julia_typecheck(t) && (&*t.ptr()).mutabl == 0
}
}
pub struct PrimitiveType;
unsafe impl JuliaTypecheck for PrimitiveType {
unsafe fn julia_typecheck(t: DataType) -> bool {
t.is::<Immutable>() && !(&*t.ptr()).layout.is_null() && t.nfields() == 0 && t.size() > 0
}
}
pub struct StructType;
unsafe impl JuliaTypecheck for StructType {
unsafe fn julia_typecheck(t: DataType) -> bool {
!t.is_abstract() && !t.is::<PrimitiveType>()
}
}
pub struct Singleton;
unsafe impl JuliaTypecheck for Singleton {
unsafe fn julia_typecheck(t: DataType) -> bool {
t.instance().is_some()
}
}
pub struct Slot;
unsafe impl JuliaTypecheck for Slot {
unsafe fn julia_typecheck(t: DataType) -> bool {
t.ptr() == jl_slotnumber_type || t.ptr() == jl_typedslot_type
}
}
pub struct GlobalRef;
impl_julia_typecheck!(GlobalRef, jl_globalref_type);
pub struct GotoNode;
impl_julia_typecheck!(GotoNode, jl_gotonode_type);
pub struct PiNode;
impl_julia_typecheck!(PiNode, jl_pinode_type);
pub struct PhiNode;
impl_julia_typecheck!(PhiNode, jl_phinode_type);
pub struct PhiCNode;
impl_julia_typecheck!(PhiCNode, jl_phicnode_type);
pub struct UpsilonNode;
impl_julia_typecheck!(UpsilonNode, jl_upsilonnode_type);
pub struct QuoteNode;
impl_julia_typecheck!(QuoteNode, jl_quotenode_type);
pub struct NewVarNode;
impl_julia_typecheck!(NewVarNode, jl_newvarnode_type);
pub struct LineNode;
impl_julia_typecheck!(LineNode, jl_linenumbernode_type);
pub struct CodeInfo;
impl_julia_typecheck!(CodeInfo, jl_code_info_type);
impl_julia_typecheck!(String, jl_string_type);
pub struct Pointer;
unsafe impl JuliaTypecheck for Pointer {
unsafe fn julia_typecheck(t: DataType) -> bool {
jl_is_cpointer_type(t.ptr().cast())
}
}
pub struct Intrinsic;
impl_julia_typecheck!(Intrinsic, jl_intrinsic_type);
pub struct Concrete;
unsafe impl JuliaTypecheck for Concrete {
unsafe fn julia_typecheck(t: DataType) -> bool {
(&*t.ptr()).isconcretetype != 0
}
}