pub mod data;
pub mod dimensions;
pub mod tracked;
#[julia_version(since = "1.11")]
use std::ptr::null_mut;
use std::{
ffi::c_void,
fmt::{Debug, Formatter, Result as FmtResult},
marker::PhantomData,
mem::MaybeUninit,
ptr::NonNull,
};
use jl_sys::{
jl_alloc_vec_any, jl_apply_array_type, jl_array_eltype, jl_array_rank, jl_array_t,
jl_array_to_string, jl_gc_add_ptr_finalizer, jl_new_struct_uninit, jl_pchar_to_array,
};
use jlrs_macros::julia_version;
use jlrs_sys::{
inlined::{jlrs_array_dims_ptr, jlrs_array_ndims_fast},
jlrs_array_data, jlrs_array_data_owner, jlrs_array_has_pointers, jlrs_array_how,
jlrs_array_is_pointer_array, jlrs_array_is_union_array, jlrs_array_len,
};
#[julia_version(until = "1.10")]
use self::dimensions::Dims;
use self::{
data::accessor::{
BitsAccessor, BitsAccessorMut, BitsUnionAccessor, BitsUnionAccessorMut,
IndeterminateAccessor, IndeterminateAccessorMut, InlineAccessor, InlineAccessorMut,
ManagedAccessor, ManagedAccessorMut, ValueAccessor, ValueAccessorMut,
},
dimensions::{ArrayDimensions, DimsExt, DimsRankAssert, DimsRankCheck, RankedDims},
tracked::{TrackedArrayBase, TrackedArrayBaseMut},
};
use super::{
string::{JuliaString, StringData},
symbol::static_symbol::{NSym, StaticSymbol, TSym},
union::Union,
};
use crate::{
catch::{catch_exceptions, unwrap_exc},
convert::ccall_types::{CCallArg, CCallReturn},
data::{
layout::{
is_bits::IsBits,
typed_layout::HasLayout,
valid_layout::{ValidField, ValidLayout},
},
managed::{
Weak, private::ManagedPriv, type_name::TypeName, type_var::TypeVar, union_all::UnionAll,
},
types::{
abstract_type::AnyType,
construct_type::{BitsUnionCtor, ConstructType, IfConcreteElse},
typecheck::Typecheck,
},
},
error::{AccessError, ArrayLayoutError, CANNOT_DISPLAY_TYPE, InstantiationError, TypeError},
memory::{
get_tls,
scope::LocalScopeExt,
target::{TargetResult, unrooted::Unrooted},
},
prelude::{DataType, JlrsResult, LocalScope, Managed, Target, TargetType, Value, ValueData},
private::Private,
};
#[repr(u8)]
#[derive(PartialEq, Debug)]
pub enum How {
InlineOrForeign = 0,
JuliaAllocated = 1,
MallocAllocated = 2,
PointerToOwner = 3,
}
#[repr(transparent)]
pub struct ArrayBase<'scope, 'data, T, const N: isize>(
NonNull<jl_array_t>,
PhantomData<&'scope ()>,
PhantomData<&'data mut ()>,
PhantomData<T>,
);
impl<T, const N: isize> Clone for ArrayBase<'_, '_, T, N> {
#[inline]
fn clone(&self) -> Self {
ArrayBase(self.0, PhantomData, PhantomData, PhantomData)
}
}
impl<T, const N: isize> Copy for ArrayBase<'_, '_, T, N> {}
pub trait ConstructTypedArray<T: ConstructType, const N: isize> {
fn array_type<'target, D, Tgt>(target: Tgt, dims: &D) -> ValueData<'target, 'static, Tgt>
where
Tgt: Target<'target>,
D: DimsExt;
fn new<'target, D, Tgt>(target: Tgt, dims: D) -> ArrayBaseResult<'target, 'static, Tgt, T, N>
where
Tgt: Target<'target>,
D: DimsExt,
{
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
if DimsRankAssert::<D, N>::NEEDS_RUNTIME_RANK_CHECK {
assert_eq!(N as usize, dims.rank());
}
unsafe {
let callback = || {
let array_type = Self::array_type(&target, &dims).as_value();
dims.alloc_array(&target, array_type)
};
let v = match catch_exceptions(callback, unwrap_exc) {
Ok(arr) => Ok(arr.ptr()),
Err(e) => Err(e),
};
target.result_from_ptr(v, Private)
}
}
unsafe fn new_unchecked<'target, D, Tgt>(
target: Tgt,
dims: D,
) -> ArrayBaseData<'target, 'static, Tgt, T, N>
where
Tgt: Target<'target>,
D: DimsExt,
{
unsafe {
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
let array_type = Self::array_type(&target, &dims).as_value();
let array = dims.alloc_array(&target, array_type);
target.data_from_ptr(array.ptr(), Private)
}
}
fn from_slice<'target, 'data, U, D, Tgt>(
target: Tgt,
data: &'data mut [U],
dims: D,
) -> JlrsResult<ArrayBaseResult<'target, 'data, Tgt, T, N>>
where
Tgt: Target<'target>,
D: DimsExt,
T: HasLayout<'static, 'static, Layout = U>,
U: ValidLayout + ValidField + IsBits,
{
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
if DimsRankAssert::<D, N>::NEEDS_RUNTIME_RANK_CHECK {
let expected = N as usize;
let found = dims.rank();
if expected != found {
Err(InstantiationError::ArrayRankMismatch { expected, found })?;
}
}
if dims.size() != data.len() {
Err(InstantiationError::ArraySizeMismatch {
vec_size: data.len(),
dim_size: dims.size(),
})?;
}
unsafe {
let callback = || {
let array_type = Self::array_type(&target, &dims).as_value();
dims.alloc_array_with_data(&target, array_type, data.as_ptr() as _)
};
let v = match catch_exceptions(callback, unwrap_exc) {
Ok(arr) => Ok(arr.ptr()),
Err(e) => Err(e),
};
Ok(target.result_from_ptr(v, Private))
}
}
unsafe fn from_slice_unchecked<'target, 'data, U, D, Tgt>(
target: Tgt,
data: &'data mut [U],
dims: D,
) -> ArrayBaseData<'target, 'data, Tgt, T, N>
where
Tgt: Target<'target>,
D: DimsExt,
T: HasLayout<'static, 'static, Layout = U>,
U: ValidLayout + ValidField + IsBits,
{
unsafe {
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
let array_type = Self::array_type(&target, &dims).as_value();
let array = dims.alloc_array_with_data(&target, array_type, data.as_ptr() as _);
target.data_from_ptr(array.ptr(), Private)
}
}
fn from_vec<'target, U, D, Tgt>(
target: Tgt,
data: Vec<U>,
dims: D,
) -> JlrsResult<ArrayBaseResult<'target, 'static, Tgt, T, N>>
where
Tgt: Target<'target>,
D: DimsExt,
T: HasLayout<'static, 'static, Layout = U>,
U: ValidLayout + ValidField + IsBits,
{
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
if DimsRankAssert::<D, N>::NEEDS_RUNTIME_RANK_CHECK {
let expected = N as usize;
let found = dims.rank();
if expected != found {
Err(InstantiationError::ArrayRankMismatch { expected, found })?;
}
}
if dims.size() != data.len() {
Err(InstantiationError::ArraySizeMismatch {
vec_size: data.len(),
dim_size: dims.size(),
})?;
}
let data = Box::leak(data.into_boxed_slice());
unsafe {
let callback = || {
let array_type = Self::array_type(&target, &dims).as_value();
let array = dims.alloc_array_with_data(&target, array_type, data.as_mut_ptr() as _);
#[cfg(not(julia_1_10))]
let mem = jlrs_sys::inlined::jlrs_array_mem(array.ptr().as_ptr());
#[cfg(julia_1_10)]
let mem = array.ptr().as_ptr().cast();
jl_gc_add_ptr_finalizer(get_tls(), mem, droparray::<U> as *mut c_void);
array
};
let v = match catch_exceptions(callback, unwrap_exc) {
Ok(arr) => Ok(arr.ptr()),
Err(e) => Err(e),
};
Ok(target.result_from_ptr(v, Private))
}
}
unsafe fn from_vec_unchecked<'target, U, D, Tgt>(
target: Tgt,
data: Vec<U>,
dims: D,
) -> ArrayBaseData<'target, 'static, Tgt, T, N>
where
Tgt: Target<'target>,
D: DimsExt,
T: HasLayout<'static, 'static, Layout = U>,
U: ValidLayout + ValidField + IsBits,
{
unsafe {
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
let data = Box::leak(data.into_boxed_slice());
let array_type = Self::array_type(&target, &dims).as_value();
let array = dims.alloc_array_with_data(&target, array_type, data.as_mut_ptr() as _);
#[cfg(not(julia_1_10))]
let mem = jlrs_sys::inlined::jlrs_array_mem(array.ptr().as_ptr());
#[cfg(julia_1_10)]
let mem = array.ptr().as_ptr().cast();
jl_gc_add_ptr_finalizer(get_tls(), mem, droparray::<U> as *mut c_void);
target.data_from_ptr(array.ptr(), Private)
}
}
fn from_slice_cloned<'target, V, U, D, Tgt>(
target: Tgt,
data: V,
dims: D,
) -> JlrsResult<ArrayBaseResult<'target, 'static, Tgt, T, N>>
where
Tgt: Target<'target>,
D: DimsExt,
T: HasLayout<'static, 'static, Layout = U>,
U: ValidLayout + ValidField + IsBits + Clone,
V: AsRef<[U]>,
{
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
if DimsRankAssert::<D, N>::NEEDS_RUNTIME_RANK_CHECK {
let expected = N as usize;
let found = dims.rank();
if expected != found {
Err(InstantiationError::ArrayRankMismatch { expected, found })?;
}
}
let data = data.as_ref();
let len = data.len();
let dim_size = dims.size();
if len != dim_size {
Err(InstantiationError::ArraySizeMismatch {
vec_size: len,
dim_size: dim_size,
})?;
}
unsafe {
let arr = match Self::new(&target, dims) {
Ok(arr) => arr,
Err(e) => return Ok(Err(e.as_value().root(target))),
};
let array_data = jlrs_array_data(arr.as_managed().unwrap(Private));
let array_data_slice = std::slice::from_raw_parts_mut(array_data as _, len);
array_data_slice.clone_from_slice(data);
Ok(Ok(arr.root(target)))
}
}
unsafe fn from_slice_cloned_unchecked<'target, V, U, D, Tgt>(
target: Tgt,
data: V,
dims: D,
) -> ArrayBaseData<'target, 'static, Tgt, T, N>
where
Tgt: Target<'target>,
D: DimsExt,
T: HasLayout<'static, 'static, Layout = U>,
U: ValidLayout + ValidField + IsBits + Clone,
V: AsRef<[U]>,
{
unsafe {
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
let data = data.as_ref();
let len = data.len();
let arr = Self::new_unchecked(&target, dims);
let array_data = jlrs_array_data(arr.as_managed().unwrap(Private));
let array_data_slice = std::slice::from_raw_parts_mut(array_data as _, len);
array_data_slice.clone_from_slice(data);
arr.root(target)
}
}
fn from_slice_copied<'target, V, U, D, Tgt>(
target: Tgt,
data: V,
dims: D,
) -> JlrsResult<ArrayBaseResult<'target, 'static, Tgt, T, N>>
where
Tgt: Target<'target>,
D: DimsExt,
T: HasLayout<'static, 'static, Layout = U>,
U: ValidLayout + ValidField + IsBits + Copy,
V: AsRef<[U]>,
{
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
if DimsRankAssert::<D, N>::NEEDS_RUNTIME_RANK_CHECK {
let expected = N as usize;
let found = dims.rank();
if expected != found {
Err(InstantiationError::ArrayRankMismatch { expected, found })?;
}
}
let data = data.as_ref();
let len = data.len();
let dim_size = dims.size();
if len != dim_size {
Err(InstantiationError::ArraySizeMismatch {
vec_size: len,
dim_size: dim_size,
})?;
}
unsafe {
let arr = match Self::new(&target, dims) {
Ok(arr) => arr,
Err(e) => return Ok(Err(e.as_value().root(target))),
};
let array_data = jlrs_array_data(arr.as_managed().unwrap(Private));
let array_data_slice = std::slice::from_raw_parts_mut(array_data as _, len);
array_data_slice.copy_from_slice(data);
Ok(Ok(arr.root(target)))
}
}
unsafe fn from_slice_copied_unchecked<'target, V, U, D, Tgt>(
target: Tgt,
data: V,
dims: D,
) -> ArrayBaseData<'target, 'static, Tgt, T, N>
where
Tgt: Target<'target>,
D: DimsExt,
T: HasLayout<'static, 'static, Layout = U>,
U: ValidLayout + ValidField + IsBits + Copy,
V: AsRef<[U]>,
{
unsafe {
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
let data = data.as_ref();
let len = data.len();
let arr = Self::new_unchecked(&target, dims);
let array_data = jlrs_array_data(arr.as_managed().unwrap(Private));
let array_data_slice = std::slice::from_raw_parts_mut(array_data as _, len);
array_data_slice.copy_from_slice(data);
arr.root(target)
}
}
}
impl<T: ConstructType, const N: isize> ConstructTypedArray<T, N> for ArrayBase<'_, '_, T, N> {
fn array_type<'target, D, Tgt>(target: Tgt, dims: &D) -> ValueData<'target, 'static, Tgt>
where
Tgt: Target<'target>,
D: DimsExt,
{
dims.array_type::<T, _>(target)
}
}
impl<const N: isize> ArrayBase<'_, '_, Unknown, N> {
pub fn new_for<'target, D, Tgt>(
target: Tgt,
ty: Value,
dims: D,
) -> ArrayBaseResult<'target, 'static, Tgt, Unknown, N>
where
Tgt: Target<'target>,
D: DimsExt,
{
const {
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
}
if DimsRankAssert::<D, N>::NEEDS_RUNTIME_RANK_CHECK {
assert_eq!(N as usize, dims.rank());
}
unsafe {
let callback = || {
let array_type = jl_apply_array_type(ty.unwrap(Private), dims.rank());
let array_type = Value::wrap_non_null(NonNull::new_unchecked(array_type), Private);
let array = dims.alloc_array(&target, array_type);
array
};
let v = match catch_exceptions(callback, unwrap_exc) {
Ok(arr) => Ok(arr.ptr()),
Err(e) => Err(e),
};
target.result_from_ptr(v, Private)
}
}
pub unsafe fn new_for_unchecked<'target, D, Tgt>(
target: Tgt,
ty: Value,
dims: D,
) -> ArrayBaseData<'target, 'static, Tgt, Unknown, N>
where
Tgt: Target<'target>,
D: DimsExt,
{
unsafe {
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
let array_type = jl_apply_array_type(ty.unwrap(Private), dims.rank());
let array_type = Value::wrap_non_null(NonNull::new_unchecked(array_type), Private);
let array = dims.alloc_array(&target, array_type);
target.data_from_ptr(array.ptr(), Private)
}
}
pub fn from_slice_for<'target, 'data, U, D, Tgt>(
target: Tgt,
ty: Value,
data: &'data mut [U],
dims: D,
) -> JlrsResult<ArrayBaseResult<'target, 'data, Tgt, Unknown, N>>
where
Tgt: Target<'target>,
D: DimsExt,
U: ValidLayout + ValidField + IsBits,
{
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
if DimsRankAssert::<D, N>::NEEDS_RUNTIME_RANK_CHECK {
let expected = N as usize;
let found = dims.rank();
if expected != found {
Err(InstantiationError::ArrayRankMismatch { expected, found })?;
}
}
if dims.size() != data.len() {
Err(InstantiationError::ArraySizeMismatch {
vec_size: data.len(),
dim_size: dims.size(),
})?;
}
if !U::valid_layout(ty) {
let value_type = ty.display_string_or(CANNOT_DISPLAY_TYPE).into();
Err(AccessError::InvalidLayout { value_type })?;
}
unsafe {
let callback = || {
let array_type = jl_apply_array_type(ty.unwrap(Private), dims.rank());
let array_type = Value::wrap_non_null(NonNull::new_unchecked(array_type), Private);
let array = dims.alloc_array_with_data(&target, array_type, data.as_ptr() as _);
array
};
let v = match catch_exceptions(callback, unwrap_exc) {
Ok(arr) => Ok(arr.ptr()),
Err(e) => Err(e),
};
Ok(target.result_from_ptr(v, Private))
}
}
pub unsafe fn from_slice_for_unchecked<'target, 'data, U, D, Tgt>(
target: Tgt,
ty: Value,
data: &'data mut [U],
dims: D,
) -> ArrayBaseData<'target, 'data, Tgt, Unknown, N>
where
Tgt: Target<'target>,
D: DimsExt,
U: ValidLayout + ValidField + IsBits,
{
unsafe {
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
let array_type = jl_apply_array_type(ty.unwrap(Private), dims.rank());
let array_type = Value::wrap_non_null(NonNull::new_unchecked(array_type), Private);
let array = dims.alloc_array_with_data(&target, array_type, data.as_ptr() as _);
target.data_from_ptr(array.ptr(), Private)
}
}
pub fn from_vec_for<'target, U, D, Tgt>(
target: Tgt,
ty: Value,
data: Vec<U>,
dims: D,
) -> JlrsResult<ArrayBaseResult<'target, 'static, Tgt, Unknown, N>>
where
Tgt: Target<'target>,
D: DimsExt,
U: ValidLayout + ValidField + IsBits,
{
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
if DimsRankAssert::<D, N>::NEEDS_RUNTIME_RANK_CHECK {
let expected = N as usize;
let found = dims.rank();
if expected != found {
Err(InstantiationError::ArrayRankMismatch { expected, found })?;
}
}
if dims.size() != data.len() {
Err(InstantiationError::ArraySizeMismatch {
vec_size: data.len(),
dim_size: dims.size(),
})?;
}
if !U::valid_layout(ty) {
let value_type = ty.display_string_or(CANNOT_DISPLAY_TYPE).into();
Err(AccessError::InvalidLayout { value_type })?;
}
let data = Box::leak(data.into_boxed_slice());
unsafe {
let callback = || {
let array_type = jl_apply_array_type(ty.unwrap(Private), dims.rank());
let array_type = Value::wrap_non_null(NonNull::new_unchecked(array_type), Private);
let array = dims.alloc_array_with_data(&target, array_type, data.as_mut_ptr() as _);
#[cfg(not(julia_1_10))]
let mem = jlrs_sys::inlined::jlrs_array_mem(array.ptr().as_ptr());
#[cfg(julia_1_10)]
let mem = array.ptr().as_ptr().cast();
jl_gc_add_ptr_finalizer(get_tls(), mem, droparray::<U> as *mut c_void);
array
};
let v = match catch_exceptions(callback, unwrap_exc) {
Ok(arr) => Ok(arr.ptr()),
Err(e) => Err(e),
};
Ok(target.result_from_ptr(v, Private))
}
}
pub unsafe fn from_vec_for_unchecked<'target, U, D, Tgt>(
target: Tgt,
ty: Value,
data: Vec<U>,
dims: D,
) -> ArrayBaseData<'target, 'static, Tgt, Unknown, N>
where
Tgt: Target<'target>,
D: DimsExt,
U: ValidLayout + ValidField + IsBits,
{
unsafe {
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
let data = Box::leak(data.into_boxed_slice());
let array_type = jl_apply_array_type(ty.unwrap(Private), dims.rank());
let array_type = Value::wrap_non_null(NonNull::new_unchecked(array_type), Private);
let array = dims.alloc_array_with_data(&target, array_type, data.as_mut_ptr() as _);
#[cfg(not(julia_1_10))]
let mem = jlrs_sys::inlined::jlrs_array_mem(array.ptr().as_ptr());
#[cfg(julia_1_10)]
let mem = array.ptr().as_ptr().cast();
jl_gc_add_ptr_finalizer(get_tls(), mem, droparray::<U> as *mut c_void);
target.data_from_ptr(array.ptr(), Private)
}
}
pub fn from_slice_cloned_for<'target, V, U, D, Tgt>(
target: Tgt,
ty: Value,
data: V,
dims: D,
) -> JlrsResult<ArrayBaseResult<'target, 'static, Tgt, Unknown, N>>
where
Tgt: Target<'target>,
D: DimsExt,
U: ValidLayout + ValidField + IsBits + Clone,
V: AsRef<[U]>,
{
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
if DimsRankAssert::<D, N>::NEEDS_RUNTIME_RANK_CHECK {
let expected = N as usize;
let found = dims.rank();
if expected != found {
Err(InstantiationError::ArrayRankMismatch { expected, found })?;
}
}
let data = data.as_ref();
let len = data.len();
let dim_size = dims.size();
if len != dim_size {
Err(InstantiationError::ArraySizeMismatch {
vec_size: len,
dim_size: dim_size,
})?;
}
if !U::valid_layout(ty) {
let value_type = ty.display_string_or(CANNOT_DISPLAY_TYPE).into();
Err(AccessError::InvalidLayout { value_type })?;
}
unsafe {
match Self::new_for(&target, ty, dims) {
Ok(arr) => {
let array_data = jlrs_array_data(arr.as_managed().unwrap(Private));
let array_data_slice = std::slice::from_raw_parts_mut(array_data as _, len);
array_data_slice.clone_from_slice(data);
Ok(Ok(arr.root(target)))
}
Err(err) => Ok(Err(err.as_value().root(target))),
}
}
}
pub unsafe fn from_slice_cloned_for_unchecked<'target, V, U, D, Tgt>(
target: Tgt,
ty: Value,
data: V,
dims: D,
) -> ArrayBaseData<'target, 'static, Tgt, Unknown, N>
where
Tgt: Target<'target>,
D: DimsExt,
U: ValidLayout + ValidField + IsBits + Clone,
V: AsRef<[U]>,
{
unsafe {
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
let data = data.as_ref();
let len = data.len();
let arr = Self::new_for_unchecked(&target, ty, dims);
let array_data = jlrs_array_data(arr.as_managed().unwrap(Private));
let array_data_slice = std::slice::from_raw_parts_mut(array_data as _, len);
array_data_slice.clone_from_slice(data);
arr.root(target)
}
}
pub fn from_slice_copied_for<'target, V, U, D, Tgt>(
target: Tgt,
ty: Value,
data: V,
dims: D,
) -> JlrsResult<ArrayBaseResult<'target, 'static, Tgt, Unknown, N>>
where
Tgt: Target<'target>,
D: DimsExt,
U: ValidLayout + ValidField + IsBits + Copy,
V: AsRef<[U]>,
{
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
if DimsRankAssert::<D, N>::NEEDS_RUNTIME_RANK_CHECK {
let expected = N as usize;
let found = dims.rank();
if expected != found {
Err(InstantiationError::ArrayRankMismatch { expected, found })?;
}
}
let data = data.as_ref();
let len = data.len();
let dim_size = dims.size();
if len != dim_size {
Err(InstantiationError::ArraySizeMismatch {
vec_size: len,
dim_size: dim_size,
})?;
}
if !U::valid_layout(ty) {
let value_type = ty.display_string_or(CANNOT_DISPLAY_TYPE).into();
Err(AccessError::InvalidLayout { value_type })?;
}
unsafe {
match Self::new_for(&target, ty, dims) {
Ok(arr) => {
let array_data = jlrs_array_data(arr.as_managed().unwrap(Private));
let array_data_slice = std::slice::from_raw_parts_mut(array_data as _, len);
array_data_slice.copy_from_slice(data);
Ok(Ok(arr.root(target)))
}
Err(err) => Ok(Err(err.as_value().root(target))),
}
}
}
pub unsafe fn from_slice_copied_for_unchecked<'target, V, U, D, Tgt>(
target: Tgt,
ty: Value,
data: V,
dims: D,
) -> ArrayBaseData<'target, 'static, Tgt, Unknown, N>
where
Tgt: Target<'target>,
D: DimsExt,
U: ValidLayout + ValidField + IsBits + Copy,
V: AsRef<[U]>,
{
unsafe {
let _ = DimsRankAssert::<D, N>::ASSERT_VALID_RANK;
let data = data.as_ref();
let len = data.len();
let arr = Self::new_for_unchecked(&target, ty, dims);
let array_data = jlrs_array_data(arr.as_managed().unwrap(Private));
let array_data_slice = std::slice::from_raw_parts_mut(array_data as _, len);
array_data_slice.copy_from_slice(data);
arr.root(target)
}
}
}
impl TypedVector<'_, '_, u8> {
pub fn from_bytes<'target, B, Tgt>(
target: Tgt,
bytes: B,
) -> ArrayBaseResult<'target, 'static, Tgt, u8, 1>
where
Tgt: Target<'target>,
B: AsRef<[u8]>,
{
unsafe {
let callback = || {
let bytes = bytes.as_ref();
jl_pchar_to_array(bytes.as_ptr() as *const _ as _, bytes.len())
};
let v = match catch_exceptions(callback, unwrap_exc) {
Ok(arr) => Ok(NonNull::new_unchecked(arr)),
Err(e) => Err(e),
};
target.result_from_ptr(v, Private)
}
}
pub unsafe fn from_bytes_unchecked<'target, B, Tgt>(
target: Tgt,
bytes: B,
) -> ArrayBaseData<'target, 'static, Tgt, u8, 1>
where
Tgt: Target<'target>,
B: AsRef<[u8]>,
{
unsafe {
let bytes = bytes.as_ref();
let array = jl_pchar_to_array(bytes.as_ptr() as *const _ as _, bytes.len());
target.data_from_ptr(NonNull::new_unchecked(array), Private)
}
}
pub fn to_jl_string<'target, Tgt>(self, target: Tgt) -> StringData<'target, Tgt>
where
Tgt: Target<'target>,
{
unsafe {
let s = jl_array_to_string(self.unwrap(Private));
let s = JuliaString::wrap_non_null(NonNull::new_unchecked(s.cast()), Private);
s.root(target)
}
}
}
impl<'scope, 'data> VectorAny<'_, '_> {
pub fn new_any<'target, Tgt>(target: Tgt, size: usize) -> VectorAnyResult<'target, 'static, Tgt>
where
Tgt: Target<'target>,
{
unsafe {
let callback = || jl_alloc_vec_any(size);
let v = match catch_exceptions(callback, unwrap_exc) {
Ok(arr) => Ok(NonNull::new_unchecked(arr)),
Err(e) => Err(e),
};
target.result_from_ptr(v, Private)
}
}
pub unsafe fn new_any_unchecked<'target, Tgt>(
target: Tgt,
size: usize,
) -> VectorAnyData<'target, 'static, Tgt>
where
Tgt: Target<'target>,
{
unsafe {
let arr = jl_alloc_vec_any(size);
target.data_from_ptr(NonNull::new_unchecked(arr), Private)
}
}
}
impl<T, const N: isize> ArrayBase<'_, '_, T, N> {
pub fn rank(self) -> i32 {
unsafe { jl_array_rank(self.unwrap(Private).cast()) }
}
pub const fn has_rank(self) -> bool {
N != -1
}
pub const fn has_rank_s() -> bool {
N != -1
}
}
impl<const N: isize> ArrayBase<'_, '_, Unknown, N> {
pub const fn has_constrained_type(self) -> bool {
false
}
pub const fn has_constrained_type_s() -> bool {
false
}
}
impl<T: ConstructType, const N: isize> ArrayBase<'_, '_, T, N> {
pub const fn has_constrained_type(self) -> bool {
true
}
pub const fn has_constrained_type_s() -> bool {
true
}
}
impl<'scope, 'data, T, const N: isize> ArrayBase<'scope, 'data, T, N> {
pub fn element_size(self) -> usize {
unsafe {
let t = self.as_value().datatype().parameter_unchecked(0);
if t.is::<DataType>() {
t.cast_unchecked::<DataType>()
.size()
.map(|sz| sz as usize)
.unwrap_or(std::mem::size_of::<Value>())
} else if t.is::<Union>() {
let u = t.cast_unchecked::<Union>();
let mut sz = 0;
let mut align = 0;
if u.isbits_size_align(&mut sz, &mut align) {
return sz;
}
std::mem::size_of::<Value>()
} else {
std::mem::size_of::<Value>()
}
}
}
pub fn element_type(self) -> Value<'scope, 'static> {
unsafe {
Value::wrap_non_null(
NonNull::new_unchecked(jl_array_eltype(self.unwrap(Private).cast()).cast()),
Private,
)
}
}
pub fn contains<L: ValidField>(self) -> bool {
L::valid_field(self.element_type())
}
pub fn length(self) -> usize {
unsafe { jlrs_array_len(self.unwrap(Private)) }
}
pub fn how(self) -> How {
let how = unsafe { jlrs_array_how(self.unwrap(Private)) };
match how {
0 => How::InlineOrForeign,
1 => How::JuliaAllocated,
2 => How::MallocAllocated,
3 => How::PointerToOwner,
_ => unreachable!(),
}
}
#[inline]
pub fn n_dims(self) -> usize {
if N != -1 {
N as usize
} else {
unsafe { jlrs_array_ndims_fast(self.unwrap(Private)) }
}
}
#[inline]
pub const fn generic_rank(self) -> isize {
N
}
#[inline]
pub fn ptr_array(self) -> bool {
unsafe { jlrs_array_is_pointer_array(self.unwrap(Private)) != 0 }
}
#[inline]
pub fn has_ptr(self) -> bool {
unsafe { jlrs_array_has_pointers(self.unwrap(Private)) != 0 }
}
#[inline]
pub fn union_array(self) -> bool {
unsafe { jlrs_array_is_union_array(self.unwrap(Private)) != 0 }
}
#[inline]
pub fn dimensions<'borrow>(&'borrow self) -> ArrayDimensions<'borrow, N> {
unsafe {
let ptr = jlrs_array_dims_ptr(self.unwrap(Private));
let n = self.n_dims() as usize;
let dims = std::slice::from_raw_parts_mut(ptr.cast(), n);
ArrayDimensions::new(dims)
}
}
#[inline]
pub unsafe fn data_ptr(self) -> *mut c_void {
unsafe { jlrs_array_data(self.unwrap(Private)) }
}
pub fn owner(self) -> Option<Value<'scope, 'data>> {
if self.how() == How::PointerToOwner {
unsafe {
return Some(Value::wrap_non_null(
NonNull::new_unchecked(jlrs_array_data_owner(self.unwrap(Private))),
Private,
));
}
}
None
}
pub fn zero_init(&self) -> bool {
let ty = self.element_type();
if ty.is::<DataType>() {
unsafe {
let ty = ty.cast_unchecked::<DataType>();
ty.zero_init()
}
} else {
true
}
}
}
impl<'scope, 'data, T, const N: isize> ArrayBase<'scope, 'data, T, N> {
pub fn track_shared(self) -> JlrsResult<TrackedArrayBase<'scope, 'data, T, N>> {
TrackedArrayBase::track_shared(self)
}
pub fn track_exclusive(self) -> JlrsResult<TrackedArrayBaseMut<'scope, 'data, T, N>> {
TrackedArrayBaseMut::track_exclusive(self)
}
}
impl<'scope, 'data, T, const N: isize> ArrayBase<'scope, 'data, T, N> {
pub fn has_bits_layout(self) -> bool {
self.has_inline_layout() && !self.has_ptr()
}
pub fn has_inline_layout(self) -> bool {
!self.ptr_array() && !self.union_array()
}
pub fn has_inline_with_refs_layout(self) -> bool {
!self.ptr_array() && !self.has_union_layout() && self.has_ptr()
}
pub fn has_union_layout(self) -> bool {
self.union_array()
}
pub fn has_value_layout(self) -> bool {
self.ptr_array()
}
pub fn has_managed_layout<M: Managed<'scope, 'data> + Typecheck>(self) -> bool {
if self.ptr_array() {
let elty = self.element_type();
if elty.is::<DataType>() {
unsafe { elty.cast_unchecked::<DataType>().is::<M>() }
} else {
elty.is::<M>()
}
} else {
false
}
}
}
impl<'scope, 'data, T, const N: isize> ArrayBase<'scope, 'data, T, N> {
pub unsafe fn bits_data<'borrow>(&'borrow self) -> BitsAccessor<'borrow, 'scope, 'data, T, T, N>
where
T: ConstructType + ValidField + IsBits,
{
unsafe {
BitsAccessor::new(self)
}
}
pub unsafe fn bits_data_with_layout<'borrow, L>(
&'borrow self,
) -> BitsAccessor<'borrow, 'scope, 'data, T, L, N>
where
T: ConstructType + HasLayout<'static, 'static, Layout = L>,
L: IsBits + ValidField,
{
unsafe {
BitsAccessor::new(self)
}
}
pub unsafe fn try_bits_data<'borrow, L>(
&'borrow self,
) -> JlrsResult<BitsAccessor<'borrow, 'scope, 'data, T, L, N>>
where
L: IsBits + ValidField,
{
unsafe {
if !self.has_bits_layout() {
Err(ArrayLayoutError::NotBits {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
let ty = self.element_type();
if !L::valid_field(ty) {
Err(TypeError::InvalidLayout {
value_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
Ok(BitsAccessor::new(self))
}
}
#[inline]
pub unsafe fn bits_data_unchecked<'borrow, L>(
&'borrow self,
) -> BitsAccessor<'borrow, 'scope, 'data, T, L, N>
where
L: IsBits + ValidField,
{
unsafe { BitsAccessor::new(self) }
}
#[inline]
pub unsafe fn bits_data_mut<'borrow>(
&'borrow mut self,
) -> BitsAccessorMut<'borrow, 'scope, 'data, T, T, N>
where
T: ConstructType + ValidField + IsBits,
{
unsafe {
BitsAccessorMut::new(self)
}
}
pub unsafe fn bits_data_mut_with_layout<'borrow, L>(
&'borrow mut self,
) -> BitsAccessorMut<'borrow, 'scope, 'data, T, L, N>
where
T: ConstructType + HasLayout<'static, 'static, Layout = L>,
L: IsBits + ValidField,
{
unsafe {
BitsAccessorMut::new(self)
}
}
pub unsafe fn try_bits_data_mut<'borrow, L>(
&'borrow mut self,
) -> JlrsResult<BitsAccessorMut<'borrow, 'scope, 'data, T, L, N>>
where
L: IsBits + ValidField,
{
unsafe {
if !self.has_bits_layout() {
Err(ArrayLayoutError::NotBits {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
let ty = self.element_type();
if !L::valid_field(ty) {
Err(TypeError::InvalidLayout {
value_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
Ok(BitsAccessorMut::new(self))
}
}
#[inline]
pub unsafe fn bits_data_mut_unchecked<'borrow, L>(
&'borrow mut self,
) -> BitsAccessorMut<'borrow, 'scope, 'data, T, L, N>
where
L: IsBits + ValidField,
{
unsafe { BitsAccessorMut::new(self) }
}
#[inline]
pub unsafe fn inline_data<'borrow>(
&'borrow self,
) -> InlineAccessor<'borrow, 'scope, 'data, T, T, N>
where
T: ConstructType + ValidField,
{
unsafe {
InlineAccessor::new(self)
}
}
#[inline]
pub unsafe fn inline_data_with_layout<'borrow, L>(
&'borrow self,
) -> InlineAccessor<'borrow, 'scope, 'data, T, L, N>
where
T: ConstructType + HasLayout<'scope, 'data, Layout = L>,
L: ValidField,
{
unsafe {
InlineAccessor::new(self)
}
}
pub unsafe fn try_inline_data<'borrow, L>(
&'borrow self,
) -> JlrsResult<InlineAccessor<'borrow, 'scope, 'data, T, L, N>>
where
L: ValidField,
{
unsafe {
if !self.has_inline_layout() {
Err(ArrayLayoutError::NotInline {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
let ty = self.element_type();
if !L::valid_field(ty) {
Err(TypeError::InvalidLayout {
value_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
Ok(InlineAccessor::new(self))
}
}
#[inline]
pub unsafe fn inline_data_unchecked<'borrow, L>(
&'borrow self,
) -> InlineAccessor<'borrow, 'scope, 'data, T, L, N>
where
L: ValidField,
{
unsafe { InlineAccessor::new(self) }
}
#[inline]
pub unsafe fn inline_data_mut<'borrow>(
&'borrow mut self,
) -> InlineAccessorMut<'borrow, 'scope, 'data, T, T, N>
where
T: ConstructType + ValidField,
{
unsafe {
InlineAccessorMut::new(self)
}
}
#[inline]
pub unsafe fn inline_data_mut_with_layout<'borrow, L>(
&'borrow mut self,
) -> InlineAccessorMut<'borrow, 'scope, 'data, T, L, N>
where
T: ConstructType + HasLayout<'scope, 'data, Layout = L>,
L: ValidField,
{
unsafe {
InlineAccessorMut::new(self)
}
}
pub unsafe fn try_inline_data_mut<'borrow, L>(
&'borrow mut self,
) -> JlrsResult<InlineAccessorMut<'borrow, 'scope, 'data, T, L, N>>
where
L: ValidField,
{
unsafe {
if !self.has_inline_layout() {
Err(ArrayLayoutError::NotInline {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
let ty = self.element_type();
if !L::valid_field(ty) {
Err(TypeError::InvalidLayout {
value_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
Ok(InlineAccessorMut::new(self))
}
}
#[inline]
pub unsafe fn inline_data_mut_unchecked<'borrow, L>(
&'borrow mut self,
) -> InlineAccessorMut<'borrow, 'scope, 'data, T, L, N>
where
L: ValidField,
{
unsafe { InlineAccessorMut::new(self) }
}
#[inline]
pub unsafe fn union_data<'borrow>(
&'borrow self,
) -> BitsUnionAccessor<'borrow, 'scope, 'data, T, N>
where
T: BitsUnionCtor,
{
unsafe {
assert!(
self.has_union_layout(),
"Array does not have a union layout"
);
BitsUnionAccessor::new(self)
}
}
pub unsafe fn try_union_data<'borrow>(
&'borrow self,
) -> JlrsResult<BitsUnionAccessor<'borrow, 'scope, 'data, T, N>> {
unsafe {
if !self.has_union_layout() {
Err(ArrayLayoutError::NotUnion {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
Ok(BitsUnionAccessor::new(self))
}
}
#[inline]
pub unsafe fn union_data_unchecked<'borrow>(
&'borrow self,
) -> BitsUnionAccessor<'borrow, 'scope, 'data, T, N> {
unsafe { BitsUnionAccessor::new(self) }
}
#[inline]
pub unsafe fn union_data_mut<'borrow>(
&'borrow mut self,
) -> BitsUnionAccessorMut<'borrow, 'scope, 'data, T, N>
where
T: BitsUnionCtor,
{
unsafe {
assert!(
self.has_union_layout(),
"Array does not have a union layout"
);
BitsUnionAccessorMut::new(self)
}
}
pub unsafe fn try_union_data_mut<'borrow>(
&'borrow mut self,
) -> JlrsResult<BitsUnionAccessorMut<'borrow, 'scope, 'data, T, N>> {
unsafe {
if !self.has_union_layout() {
Err(ArrayLayoutError::NotUnion {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
Ok(BitsUnionAccessorMut::new(self))
}
}
#[inline]
pub unsafe fn union_data_mut_unchecked<'borrow>(
&'borrow mut self,
) -> BitsUnionAccessorMut<'borrow, 'scope, 'data, T, N> {
unsafe { BitsUnionAccessorMut::new(self) }
}
#[inline]
pub unsafe fn managed_data<'borrow>(
&'borrow self,
) -> ManagedAccessor<'borrow, 'scope, 'data, T, T, N>
where
T: Managed<'scope, 'data> + ConstructType,
{
unsafe {
ManagedAccessor::new(self)
}
}
pub unsafe fn try_managed_data<'borrow, L>(
&'borrow self,
) -> JlrsResult<ManagedAccessor<'borrow, 'scope, 'data, T, L, N>>
where
L: Managed<'scope, 'data> + Typecheck,
{
unsafe {
if !self.has_managed_layout::<L>() {
Err(ArrayLayoutError::NotManaged {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
name: L::NAME.into(),
})?;
}
Ok(ManagedAccessor::new(self))
}
}
#[inline]
pub unsafe fn managed_data_unchecked<'borrow, L>(
&'borrow self,
) -> ManagedAccessor<'borrow, 'scope, 'data, T, L, N>
where
L: Managed<'scope, 'data>,
{
unsafe { ManagedAccessor::new(self) }
}
#[inline]
pub unsafe fn managed_data_mut<'borrow>(
&'borrow mut self,
) -> ManagedAccessorMut<'borrow, 'scope, 'data, T, T, N>
where
T: Managed<'scope, 'data> + ConstructType,
{
unsafe {
ManagedAccessorMut::new(self)
}
}
pub unsafe fn try_managed_data_mut<'borrow, L>(
&'borrow mut self,
) -> JlrsResult<ManagedAccessorMut<'borrow, 'scope, 'data, T, L, N>>
where
L: Managed<'scope, 'data> + Typecheck,
{
unsafe {
if !self.has_managed_layout::<L>() {
Err(ArrayLayoutError::NotManaged {
element_type: self.element_type().display_string_or(CANNOT_DISPLAY_TYPE),
name: L::NAME.into(),
})?;
}
Ok(ManagedAccessorMut::new(self))
}
}
#[inline]
pub unsafe fn managed_data_mut_unchecked<'borrow, L>(
&'borrow mut self,
) -> ManagedAccessorMut<'borrow, 'scope, 'data, T, L, N>
where
L: Managed<'scope, 'data>,
{
unsafe { ManagedAccessorMut::new(self) }
}
#[inline]
pub unsafe fn value_data<'borrow>(&'borrow self) -> ValueAccessor<'borrow, 'scope, 'data, T, N>
where
T: Managed<'scope, 'data> + ConstructType,
{
unsafe {
ValueAccessor::new(self)
}
}
pub unsafe fn try_value_data<'borrow>(
&'borrow self,
) -> JlrsResult<ValueAccessor<'borrow, 'scope, 'data, T, N>> {
unsafe {
if !self.has_value_layout() {
Err(ArrayLayoutError::NotPointer {
element_type: self.element_type().error_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
Ok(ValueAccessor::new(self))
}
}
#[inline]
pub unsafe fn value_data_unchecked<'borrow>(
&'borrow self,
) -> ValueAccessor<'borrow, 'scope, 'data, T, N> {
unsafe { ValueAccessor::new(self) }
}
#[inline]
pub unsafe fn value_data_mut<'borrow>(
&'borrow mut self,
) -> ValueAccessorMut<'borrow, 'scope, 'data, T, N>
where
T: Managed<'scope, 'data> + ConstructType,
{
unsafe {
ValueAccessorMut::new(self)
}
}
pub unsafe fn try_value_data_mut<'borrow>(
&'borrow mut self,
) -> JlrsResult<ValueAccessorMut<'borrow, 'scope, 'data, T, N>> {
unsafe {
if !self.has_value_layout() {
Err(ArrayLayoutError::NotPointer {
element_type: self.element_type().error_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
Ok(ValueAccessorMut::new(self))
}
}
#[inline]
pub unsafe fn value_data_mut_unchecked<'borrow>(
&'borrow mut self,
) -> ValueAccessorMut<'borrow, 'scope, 'data, T, N> {
unsafe { ValueAccessorMut::new(self) }
}
#[inline]
pub unsafe fn indeterminate_data<'borrow>(
&'borrow self,
) -> IndeterminateAccessor<'borrow, 'scope, 'data, T, N> {
unsafe { IndeterminateAccessor::new(self) }
}
#[inline]
pub unsafe fn indeterminate_data_mut<'borrow>(
&'borrow mut self,
) -> IndeterminateAccessorMut<'borrow, 'scope, 'data, T, N> {
unsafe { IndeterminateAccessorMut::new(self) }
}
}
impl<'scope, 'data, T> ArrayBase<'scope, 'data, T, -1> {
pub fn set_rank<const N: isize>(self) -> JlrsResult<ArrayBase<'scope, 'data, T, N>> {
if self.n_dims() as isize != N {
Err(ArrayLayoutError::RankMismatch {
found: self.n_dims() as _,
provided: N,
})?;
}
unsafe { Ok(self.set_rank_unchecked()) }
}
#[inline]
pub unsafe fn set_rank_unchecked<const N: isize>(self) -> ArrayBase<'scope, 'data, T, N> {
ArrayBase(
self.unwrap_non_null(Private),
PhantomData,
PhantomData,
PhantomData,
)
}
}
impl<'scope, 'data, const N: isize> ArrayBase<'scope, 'data, Unknown, N> {
pub fn set_type<T: ConstructType>(self) -> JlrsResult<ArrayBase<'scope, 'data, T, N>> {
unsafe {
let unrooted = Unrooted::new();
let constructed = T::construct_type(unrooted).as_value();
let elem_ty = self.element_type();
if constructed != elem_ty {
Err(TypeError::IncompatibleType {
element_type: constructed.display_string_or(CANNOT_DISPLAY_TYPE),
value_type: elem_ty.display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
Ok(self.set_type_unchecked())
}
}
#[inline]
pub unsafe fn set_type_unchecked<T: ConstructType>(self) -> ArrayBase<'scope, 'data, T, N> {
ArrayBase(
self.unwrap_non_null(Private),
PhantomData,
PhantomData,
PhantomData,
)
}
}
impl<'scope, 'data, T, const N: isize> ArrayBase<'scope, 'data, T, N> {
#[inline]
pub fn forget_rank(self) -> ArrayBase<'scope, 'data, T, -1> {
ArrayBase(
self.unwrap_non_null(Private),
PhantomData,
PhantomData,
PhantomData,
)
}
#[inline]
pub fn forget_type(self) -> ArrayBase<'scope, 'data, Unknown, N> {
ArrayBase(
self.unwrap_non_null(Private),
PhantomData,
PhantomData,
PhantomData,
)
}
#[inline]
pub fn assert_rank(self) {
if N == -1 {
return;
}
let rank = self.rank();
assert!(rank as isize == N);
}
}
impl<'scope, 'data, T: ConstructType, const N: isize> ArrayBase<'scope, 'data, T, N> {
pub fn assert_type(self) {
unsafe {
let unrooted = Unrooted::new();
unrooted.local_scope::<_, 1>(|mut frame| {
let ty = T::construct_type(&mut frame);
assert_eq!(ty, self.element_type());
});
}
}
}
pub enum Unknown {}
pub type ArrayBaseData<'target, 'data, Tgt, T, const N: isize> =
<Tgt as TargetType<'target>>::Data<'data, ArrayBase<'target, 'data, T, N>>;
pub type ArrayBaseResult<'target, 'data, Tgt, T, const N: isize> =
TargetResult<'target, 'data, ArrayBase<'target, 'data, T, N>, Tgt>;
pub type Array<'scope, 'data> = ArrayBase<'scope, 'data, Unknown, -1>;
pub type WeakArray<'scope, 'data> = Weak<'scope, 'data, Array<'scope, 'data>>;
pub type ArrayRet = WeakArray<'static, 'static>;
pub type ArrayData<'target, 'data, Tgt> =
<Tgt as TargetType<'target>>::Data<'data, Array<'target, 'data>>;
pub type ArrayResult<'target, 'data, Tgt> =
TargetResult<'target, 'data, Array<'target, 'data>, Tgt>;
pub type Vector<'scope, 'data> = ArrayBase<'scope, 'data, Unknown, 1>;
pub type WeakVector<'scope, 'data> = Weak<'scope, 'data, Vector<'scope, 'data>>;
pub type VectorRet = WeakVector<'static, 'static>;
pub type VectorData<'target, 'data, Tgt> =
<Tgt as TargetType<'target>>::Data<'data, Vector<'target, 'data>>;
pub type VectorResult<'target, 'data, Tgt> =
TargetResult<'target, 'data, Vector<'target, 'data>, Tgt>;
pub type VectorAny<'scope, 'data> = ArrayBase<'scope, 'data, Value<'scope, 'data>, 1>;
pub type WeakVectorAny<'scope, 'data> = Weak<'scope, 'data, VectorAny<'scope, 'data>>;
pub type VectorAnyRet = WeakVectorAny<'static, 'static>;
pub type VectorAnyData<'target, 'data, Tgt> =
<Tgt as TargetType<'target>>::Data<'data, VectorAny<'target, 'data>>;
pub type VectorAnyResult<'target, 'data, Tgt> =
TargetResult<'target, 'data, VectorAny<'target, 'data>, Tgt>;
pub type Matrix<'scope, 'data> = ArrayBase<'scope, 'data, Unknown, 2>;
pub type WeakMatrix<'scope, 'data> = Weak<'scope, 'data, Matrix<'scope, 'data>>;
pub type MatrixRet = WeakMatrix<'static, 'static>;
pub type MatrixData<'target, 'data, Tgt> =
<Tgt as TargetType<'target>>::Data<'data, Matrix<'target, 'data>>;
pub type MatrixResult<'target, 'data, Tgt> =
TargetResult<'target, 'data, Matrix<'target, 'data>, Tgt>;
pub type TypedArray<'scope, 'data, T> = ArrayBase<'scope, 'data, T, -1>;
pub type WeakTypedArray<'scope, 'data, T> = Weak<'scope, 'data, TypedArray<'scope, 'data, T>>;
pub type TypedArrayRet<T> = WeakTypedArray<'static, 'static, T>;
pub type TypedArrayData<'target, 'data, Tgt, T> =
<Tgt as TargetType<'target>>::Data<'data, TypedArray<'target, 'data, T>>;
pub type TypedArrayResult<'target, 'data, Tgt, T> =
TargetResult<'target, 'data, TypedArray<'target, 'data, T>, Tgt>;
pub type TypedVector<'scope, 'data, T> = ArrayBase<'scope, 'data, T, 1>;
pub type WeakTypedVector<'scope, 'data, T> = Weak<'scope, 'data, TypedVector<'scope, 'data, T>>;
pub type TypedVectorRet<T> = WeakTypedVector<'static, 'static, T>;
pub type TypedVectorData<'target, 'data, Tgt, T> =
<Tgt as TargetType<'target>>::Data<'data, TypedVector<'target, 'data, T>>;
pub type TypedVectorResult<'target, 'data, Tgt, T> =
TargetResult<'target, 'data, TypedVector<'target, 'data, T>, Tgt>;
pub type TypedMatrix<'scope, 'data, T> = ArrayBase<'scope, 'data, T, 2>;
pub type WeakTypedMatrix<'scope, 'data, T> = Weak<'scope, 'data, TypedMatrix<'scope, 'data, T>>;
pub type TypedMatrixRet<T> = WeakTypedMatrix<'static, 'static, T>;
pub type TypedMatrixData<'target, 'data, Tgt, T> =
<Tgt as TargetType<'target>>::Data<'data, TypedMatrix<'target, 'data, T>>;
pub type TypedMatrixResult<'target, 'data, Tgt, T> =
TargetResult<'target, 'data, TypedMatrix<'target, 'data, T>, Tgt>;
pub type RankedArray<'scope, 'data, const N: isize> = ArrayBase<'scope, 'data, Unknown, N>;
pub type WeakRankedArray<'scope, 'data, const N: isize> =
Weak<'scope, 'data, RankedArray<'scope, 'data, N>>;
pub type RankedArrayRet<const N: isize> = WeakRankedArray<'static, 'static, N>;
pub type RankedArrayData<'target, 'data, Tgt, const N: isize> =
<Tgt as TargetType<'target>>::Data<'data, RankedArray<'target, 'data, N>>;
pub type RankedArrayResult<'target, 'data, Tgt, const N: isize> =
TargetResult<'target, 'data, RankedArray<'target, 'data, N>, Tgt>;
pub type TypedRankedArray<'scope, 'data, T, const N: isize> = ArrayBase<'scope, 'data, T, N>;
pub type WeakTypedRankedArray<'scope, 'data, T, const N: isize> =
Weak<'scope, 'data, TypedRankedArray<'scope, 'data, T, N>>;
pub type TypedRankedArrayRet<T, const N: isize> = WeakTypedRankedArray<'static, 'static, T, N>;
pub type TypedRankedArrayData<'target, 'data, Tgt, T, const N: isize> =
<Tgt as TargetType<'target>>::Data<'data, TypedRankedArray<'target, 'data, T, N>>;
pub type TypedRankedArrayResult<'target, 'data, Tgt, T, const N: isize> =
TargetResult<'target, 'data, TypedRankedArray<'target, 'data, T, N>, Tgt>;
unsafe impl<'scope, 'data, const N: isize> Typecheck for ArrayBase<'scope, 'data, Unknown, N> {
fn typecheck(ty: DataType) -> bool {
let unrooted = ty.unrooted_target();
if ty.type_name().unwrap(Private) != TypeName::of_array(&unrooted).unwrap(Private) {
return false;
}
if N >= 0 {
unsafe {
let param = ty.parameter_unchecked(1);
if !param.is::<isize>() || param.unbox_unchecked::<isize>() != N {
return false;
}
}
}
true
}
}
unsafe impl<'scope, 'data, T: ConstructType, const N: isize> Typecheck
for ArrayBase<'scope, 'data, T, N>
{
fn typecheck(ty: DataType) -> bool {
let unrooted = ty.unrooted_target();
if ty.type_name().unwrap(Private) != TypeName::of_array(&unrooted).unwrap(Private) {
return false;
}
if N >= 0 {
unsafe {
let param = ty.parameter_unchecked(1);
if !param.is::<isize>() || param.unbox_unchecked::<isize>() != N {
return false;
}
}
}
unrooted.local_scope::<_, 1>(|mut frame| {
let elem_ty = unsafe { ty.parameter_unchecked(0) };
let constructed_ty = T::construct_type(&mut frame);
if elem_ty.is::<TypeVar>() && constructed_ty.is::<TypeVar>() {
unsafe {
let et = elem_ty.cast_unchecked::<TypeVar>();
let ct = constructed_ty.cast_unchecked::<TypeVar>();
return et.name() == ct.name()
&& et.lower_bound(&frame).as_value() == ct.lower_bound(&frame).as_value()
&& et.upper_bound(&frame).as_value() == ct.upper_bound(&frame).as_value();
}
}
elem_ty == constructed_ty
})
}
}
impl<T, const N: isize> Debug for ArrayBase<'_, '_, T, N> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self.display_string() {
Ok(s) => write!(f, "{}", s),
Err(e) => write!(f, "<Cannot display value: {}>", e),
}
}
}
impl<'scope, 'data, T, const N: isize> ManagedPriv<'scope, 'data>
for ArrayBase<'scope, 'data, T, N>
{
type Wraps = jl_array_t;
type WithLifetimes<'target, 'da> = ArrayBase<'target, 'da, T, N>;
const NAME: &'static str = "Array";
unsafe fn wrap_non_null(inner: NonNull<Self::Wraps>, _: crate::private::Private) -> Self {
ArrayBase(inner, PhantomData, PhantomData, PhantomData)
}
fn unwrap_non_null(self, _: crate::private::Private) -> NonNull<Self::Wraps> {
self.0
}
}
unsafe impl<const N: isize> ValidField for Option<WeakRankedArray<'_, '_, N>> {
fn valid_field(v: Value) -> bool {
if v.is::<DataType>() {
let dt = unsafe { v.cast_unchecked::<DataType>() };
let is_array = dt.is::<Array>();
if !is_array {
return false;
}
let parameters = dt.parameters();
let parameters = parameters.data();
if N != -1 {
unsafe {
let unrooted = Unrooted::new();
let rank_param = parameters.get(unrooted, 1).unwrap_unchecked().as_value();
if !rank_param.is::<isize>() || rank_param.unbox_unchecked::<isize>() != N {
return false;
}
}
}
true
} else if v.is::<UnionAll>() {
let ua = unsafe { v.cast_unchecked::<UnionAll>() };
let dt = ua.base_type();
if !dt.is::<Array>() {
return false;
}
let parameters = dt.parameters();
let parameters = parameters.data();
if N != -1 {
unsafe {
let unrooted = Unrooted::new();
let rank_param = parameters.get(unrooted, 1).unwrap_unchecked().as_value();
if !rank_param.is::<isize>() || rank_param.unbox_unchecked::<isize>() != N {
return false;
}
}
}
true
} else {
false
}
}
}
unsafe impl<T: ConstructType, const N: isize> ValidField
for Option<WeakTypedRankedArray<'_, '_, T, N>>
{
fn valid_field(v: Value) -> bool {
if v.is::<DataType>() {
let dt = unsafe { v.cast_unchecked::<DataType>() };
if !dt.is::<Array>() {
return false;
}
let parameters = dt.parameters();
let parameters = parameters.data();
if N != -1 {
unsafe {
let unrooted = Unrooted::new();
let rank_param = parameters.get(unrooted, 1).unwrap_unchecked().as_value();
if !rank_param.is::<isize>() || rank_param.unbox_unchecked::<isize>() != N {
return false;
}
}
}
unsafe {
let unrooted = Unrooted::new();
unrooted.local_scope::<_, 1>(|mut frame| {
let ty = T::construct_type(&mut frame);
let elem_ty = parameters.get(unrooted, 0).unwrap_unchecked().as_value();
ty == elem_ty
})
}
} else {
false
}
}
}
unsafe impl<'scope, 'data, T: ConstructType, const N: isize> ConstructType
for TypedRankedArray<'scope, 'data, T, N>
{
type Static = TypedRankedArray<'static, 'static, T::Static, N>;
fn construct_type_uncached<'target, Tgt>(
target: Tgt,
) -> crate::prelude::ValueData<'target, 'static, Tgt>
where
Tgt: Target<'target>,
{
let ty = UnionAll::array_type(&target);
if N == -1 {
target.with_local_scope::<_, 2>(|target, mut frame| unsafe {
let elty = T::construct_type(&mut frame);
let tn_n = ty.body().cast_unchecked::<UnionAll>().var();
let applied = ty.apply_types_unchecked(&mut frame, [elty, tn_n.as_value()]);
UnionAll::rewrap(target, applied.cast_unchecked::<DataType>())
})
} else {
target.with_local_scope::<_, 3>(|target, mut frame| unsafe {
let elty = T::construct_type(&mut frame);
let n = Value::new(&mut frame, N);
let applied = ty.apply_types_unchecked(&mut frame, [elty, n]);
UnionAll::rewrap(target, applied.cast_unchecked::<DataType>())
})
}
}
fn base_type<'target, Tgt>(target: &Tgt) -> Option<Value<'target, 'static>>
where
Tgt: Target<'target>,
{
Some(UnionAll::array_type(target).as_value())
}
fn construct_type_with_env_uncached<'target, Tgt>(
target: Tgt,
env: &crate::data::types::construct_type::TypeVarEnv,
) -> ValueData<'target, 'static, Tgt>
where
Tgt: Target<'target>,
{
let ty = UnionAll::array_type(&target);
if N == -1 {
let n_sym = NSym::get_symbol(&target);
let n_param = match env.get(n_sym) {
Some(n_param) => n_param.as_value(),
_ => ty.base_type().parameter(1).unwrap(),
};
target.with_local_scope::<_, 2>(|target, mut frame| unsafe {
let t = T::construct_type_with_env(&mut frame, env);
let applied = ty.apply_types_unchecked(&mut frame, [t, n_param]);
assert!(applied.is::<DataType>());
applied
.cast_unchecked::<DataType>()
.wrap_with_env(target, env)
})
} else {
target.with_local_scope::<_, 3>(|target, mut frame| unsafe {
let t = T::construct_type_with_env(&mut frame, env);
let n = Value::new(&mut frame, N);
let applied = ty.apply_types_unchecked(&mut frame, [t, n]);
assert!(applied.is::<DataType>());
applied
.cast_unchecked::<DataType>()
.wrap_with_env(target, env)
})
}
}
}
unsafe impl<'scope, 'data, const N: isize> ConstructType for RankedArray<'scope, 'data, N> {
type Static = RankedArray<'static, 'static, N>;
fn construct_type_uncached<'target, Tgt>(
target: Tgt,
) -> crate::prelude::ValueData<'target, 'static, Tgt>
where
Tgt: Target<'target>,
{
let ty = UnionAll::array_type(&target);
if N == -1 {
ty.as_value().root(target)
} else {
target.with_local_scope::<_, 3>(|target, mut frame| unsafe {
let tn_t = TypeVar::new_unchecked(&mut frame, "T", None, None);
let n = Value::new(&mut frame, N);
let applied = ty.apply_types_unchecked(&mut frame, [tn_t.as_value(), n]);
UnionAll::rewrap(target, applied.cast_unchecked::<DataType>())
})
}
}
#[inline]
fn base_type<'target, Tgt>(target: &Tgt) -> Option<Value<'target, 'static>>
where
Tgt: Target<'target>,
{
Some(UnionAll::array_type(target).as_value())
}
fn construct_type_with_env_uncached<'target, Tgt>(
target: Tgt,
env: &crate::data::types::construct_type::TypeVarEnv,
) -> ValueData<'target, 'static, Tgt>
where
Tgt: Target<'target>,
{
let ty = UnionAll::array_type(&target);
let t_sym = TSym::get_symbol(&target);
let t_param = env.get(t_sym).expect("TypeVar T is not in env");
if N == -1 {
let n_sym = NSym::get_symbol(&target);
let n_param = match env.get(n_sym) {
Some(n_param) => n_param.as_value(),
_ => unsafe {
ty.body()
.cast_unchecked::<UnionAll>()
.body()
.cast_unchecked::<DataType>()
.parameter(1)
.unwrap()
},
};
unsafe { ty.apply_types_unchecked(target, [t_param.as_value(), n_param]) }
} else {
target.with_local_scope::<_, 1>(|target, mut frame| unsafe {
let n = Value::new(&mut frame, N);
let applied = ty.apply_types_unchecked(target, [t_param.as_value(), n]);
applied
})
}
}
}
unsafe impl<'scope, 'data, const N: isize> CCallArg for RankedArray<'scope, 'data, N> {
type CCallArgType = AnyType;
type FunctionArgType = Self;
}
unsafe impl<const N: isize> CCallReturn for RankedArrayRet<N> {
type CCallReturnType = AnyType;
type FunctionReturnType = RankedArray<'static, 'static, N>;
type ReturnAs = Self;
#[inline]
unsafe fn return_or_throw(self) -> Self::ReturnAs {
self
}
}
unsafe impl<'scope, 'data, T: ConstructType, const N: isize> CCallArg
for TypedRankedArray<'scope, 'data, T, N>
{
type CCallArgType = IfConcreteElse<Self, AnyType>;
type FunctionArgType = Self;
}
unsafe impl<T: ConstructType, const N: isize> CCallReturn for TypedRankedArrayRet<T, N> {
type CCallReturnType = IfConcreteElse<TypedRankedArray<'static, 'static, T, N>, AnyType>;
type FunctionReturnType = TypedRankedArray<'static, 'static, T, N>;
type ReturnAs = Self;
#[inline]
unsafe fn return_or_throw(self) -> Self::ReturnAs {
self
}
}
#[inline]
pub(crate) fn sized_dim_tuple<'target, D, Tgt>(
target: Tgt,
dims: &D,
) -> ValueData<'target, 'static, Tgt>
where
D: RankedDims,
Tgt: Target<'target>,
{
unsafe {
let dims_type = dims.dimension_object(&target).as_managed();
let tuple = jl_new_struct_uninit(dims_type.unwrap(Private));
{
let slice =
std::slice::from_raw_parts_mut(tuple as *mut MaybeUninit<usize>, D::RANK as _);
dims.fill_tuple(slice, Private);
}
Value::wrap_non_null(NonNull::new_unchecked(tuple), Private).root(target)
}
}
#[inline]
pub(crate) fn unsized_dim_tuple<'target, D, Tgt>(
target: Tgt,
dims: &D,
) -> ValueData<'target, 'static, Tgt>
where
D: DimsExt,
Tgt: Target<'target>,
{
unsafe {
let dims_type = dims.dimension_object(&target).as_managed();
let tuple = jl_new_struct_uninit(dims_type.unwrap(Private));
{
let slice =
std::slice::from_raw_parts_mut(tuple as *mut MaybeUninit<usize>, dims.rank());
dims.fill_tuple(slice, Private);
}
Value::wrap_non_null(NonNull::new_unchecked(tuple), Private).root(target)
}
}
#[julia_version(until = "1.10")]
unsafe extern "C" fn droparray<T>(a: Array) {
unsafe {
let sz = a.dimensions().size();
let data_ptr = a.data_ptr().cast::<T>();
let data = Vec::from_raw_parts(data_ptr, sz, sz);
std::mem::drop(data);
}
}
#[julia_version(since = "1.11")]
unsafe extern "C" fn droparray<T>(a: *mut c_void) {
unsafe {
#[repr(C)]
struct GenericMemory<T> {
length: usize,
ptr: *mut T,
}
let a = NonNull::new_unchecked(a as *mut GenericMemory<T>).as_mut();
let v = Vec::from_raw_parts(a.ptr as *mut T, a.length, a.length);
a.ptr = null_mut();
a.length = 0;
std::mem::drop(v);
}
}