use std::{marker::PhantomData, ptr::NonNull};
#[julia_version(since = "1.7")]
use jl_sys::jl_opaque_closure_type;
#[julia_version(until = "1.6")]
use jl_sys::jl_vararg_type;
use jl_sys::{
jl_abstractarray_type, jl_anytuple_type_type, jl_apply_type, jl_array_type, jl_densearray_type,
jl_llvmpointer_type, jl_namedtuple_type, jl_pointer_type, jl_ref_type, jl_type_type,
jl_type_unionall, jl_unionall_t, jl_unionall_type, jl_value_t,
};
use jlrs_macros::julia_version;
use super::{
value::{ValueData, ValueResult},
Managed, Ref,
};
use crate::{
data::managed::{datatype::DataType, private::ManagedPriv, type_var::TypeVar, value::Value},
impl_julia_typecheck,
memory::target::{ExtendedTarget, Target},
private::Private,
};
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct UnionAll<'scope>(NonNull<jl_unionall_t>, PhantomData<&'scope ()>);
impl<'scope> UnionAll<'scope> {
pub fn new<'target, T>(
target: T,
tvar: TypeVar,
body: Value<'_, 'static>,
) -> ValueResult<'target, 'static, T>
where
T: Target<'target>,
{
use std::mem::MaybeUninit;
use crate::catch::catch_exceptions;
unsafe {
let mut callback = |result: &mut MaybeUninit<*mut jl_value_t>| {
let res = jl_type_unionall(tvar.unwrap(Private), body.unwrap(Private));
result.write(res);
Ok(())
};
let res = match catch_exceptions(&mut callback).unwrap() {
Ok(ptr) => Ok(NonNull::new_unchecked(ptr)),
Err(e) => Err(e.ptr()),
};
target.result_from_ptr(res, Private)
}
}
pub unsafe fn new_unchecked<'target, T>(
target: T,
tvar: TypeVar,
body: Value<'_, 'static>,
) -> ValueData<'target, 'static, T>
where
T: Target<'target>,
{
let ua = jl_type_unionall(tvar.unwrap(Private), body.unwrap(Private));
target.data_from_ptr(NonNull::new_unchecked(ua), Private)
}
pub fn base_type(self) -> DataType<'scope> {
let mut b = self;
while let Ok(body_ua) = b.body().cast::<UnionAll>() {
b = body_ua;
}
b.body().cast::<DataType>().unwrap()
}
pub fn body(self) -> Value<'scope, 'static> {
unsafe {
let body = self.unwrap_non_null(Private).as_ref().body;
debug_assert!(!body.is_null());
Value::wrap_non_null(NonNull::new_unchecked(body), Private)
}
}
pub fn var(self) -> TypeVar<'scope> {
unsafe {
let var = self.unwrap_non_null(Private).as_ref().var;
debug_assert!(!var.is_null());
TypeVar::wrap_non_null(NonNull::new_unchecked(var), Private)
}
}
pub unsafe fn apply_types<'target, 'params, V, T>(
self,
target: T,
types: V,
) -> ValueResult<'target, 'static, T>
where
V: AsRef<[Value<'params, 'static>]>,
T: Target<'target>,
{
use std::mem::MaybeUninit;
use crate::catch::catch_exceptions;
let types = types.as_ref();
let n = types.len();
let types_ptr = types.as_ptr() as *mut *mut jl_value_t;
unsafe {
let mut callback = |result: &mut MaybeUninit<*mut jl_value_t>| {
let v = jl_apply_type(self.as_value().unwrap(Private), types_ptr, n);
result.write(v);
Ok(())
};
let res = match catch_exceptions(&mut callback).unwrap() {
Ok(ptr) => Ok(NonNull::new_unchecked(ptr)),
Err(e) => Err(e.ptr()),
};
target.result_from_ptr(res, Private)
}
}
pub fn rewrap<'target, T: Target<'target>>(
target: ExtendedTarget<'target, '_, '_, T>,
ty: DataType,
) -> ValueData<'target, 'static, T> {
let (target, frame) = target.split();
frame
.scope(|mut frame| {
let params = ty.parameters();
let params = params.data().as_slice();
let mut body = ty.as_value();
for param in params.iter().copied() {
unsafe {
let param = param.unwrap().as_value();
if let Ok(tvar) = param.cast::<TypeVar>() {
body = UnionAll::new_unchecked(&mut frame, tvar, body).as_value();
}
}
}
Ok(body.root(target))
})
.unwrap()
}
pub unsafe fn apply_types_unchecked<'target, 'params, V, T>(
self,
target: T,
types: V,
) -> ValueData<'target, 'static, T>
where
V: AsRef<[Value<'params, 'static>]>,
T: Target<'target>,
{
let types = types.as_ref();
let n = types.len();
let types_ptr = types.as_ptr() as *mut *mut jl_value_t;
let applied = jl_apply_type(self.as_value().unwrap(Private), types_ptr, n);
debug_assert!(!applied.is_null());
target.data_from_ptr(NonNull::new_unchecked(applied), Private)
}
}
impl<'base> UnionAll<'base> {
pub fn type_type<T>(_: &T) -> Self
where
T: Target<'base>,
{
unsafe { Self::wrap_non_null(NonNull::new_unchecked(jl_type_type), Private) }
}
pub fn anytuple_type_type<T>(_: &T) -> Self
where
T: Target<'base>,
{
unsafe { Self::wrap_non_null(NonNull::new_unchecked(jl_anytuple_type_type), Private) }
}
#[julia_version(until = "1.6")]
pub fn vararg_type<T>(_: &T) -> Self
where
T: Target<'base>,
{
unsafe { Self::wrap_non_null(NonNull::new_unchecked(jl_vararg_type), Private) }
}
pub fn abstractarray_type<T>(_: &T) -> Self
where
T: Target<'base>,
{
unsafe { Self::wrap_non_null(NonNull::new_unchecked(jl_abstractarray_type), Private) }
}
#[julia_version(since = "1.7")]
pub fn opaque_closure_type<T>(_: &T) -> Self
where
T: Target<'base>,
{
unsafe { Self::wrap_non_null(NonNull::new_unchecked(jl_opaque_closure_type), Private) }
}
pub fn densearray_type<T>(_: &T) -> Self
where
T: Target<'base>,
{
unsafe { Self::wrap_non_null(NonNull::new_unchecked(jl_densearray_type), Private) }
}
pub fn array_type<T>(_: &T) -> Self
where
T: Target<'base>,
{
unsafe { Self::wrap_non_null(NonNull::new_unchecked(jl_array_type), Private) }
}
pub fn pointer_type<T>(_: &T) -> Self
where
T: Target<'base>,
{
unsafe { Self::wrap_non_null(NonNull::new_unchecked(jl_pointer_type), Private) }
}
pub fn llvmpointer_type<T>(_: &T) -> Self
where
T: Target<'base>,
{
unsafe { Self::wrap_non_null(NonNull::new_unchecked(jl_llvmpointer_type), Private) }
}
pub fn ref_type<T>(_: &T) -> Self
where
T: Target<'base>,
{
unsafe { Self::wrap_non_null(NonNull::new_unchecked(jl_ref_type), Private) }
}
pub fn namedtuple_type<T>(_: &T) -> Self
where
T: Target<'base>,
{
unsafe { Self::wrap_non_null(NonNull::new_unchecked(jl_namedtuple_type), Private) }
}
}
impl_julia_typecheck!(UnionAll<'scope>, jl_unionall_type, 'scope);
impl_debug!(UnionAll<'_>);
impl<'scope> ManagedPriv<'scope, '_> for UnionAll<'scope> {
type Wraps = jl_unionall_t;
type TypeConstructorPriv<'target, 'da> = UnionAll<'target>;
const NAME: &'static str = "UnionAll";
unsafe fn wrap_non_null(inner: NonNull<Self::Wraps>, _: Private) -> Self {
Self(inner, PhantomData)
}
fn unwrap_non_null(self, _: Private) -> NonNull<Self::Wraps> {
self.0
}
}
impl_construct_type_managed!(UnionAll<'_>, jl_unionall_type);
pub type UnionAllRef<'scope> = Ref<'scope, 'static, UnionAll<'scope>>;
pub type UnionAllRet = Ref<'static, 'static, UnionAll<'static>>;
impl_valid_layout!(UnionAllRef, UnionAll);
use crate::memory::target::target_type::TargetType;
pub type UnionAllData<'target, T> = <T as TargetType<'target>>::Data<'static, UnionAll<'target>>;
pub type UnionAllResult<'target, T> =
<T as TargetType<'target>>::Result<'static, UnionAll<'target>>;
impl_ccall_arg_managed!(UnionAll, 1);
impl_into_typed!(UnionAll);