use std::{
fmt::{Debug, Formatter, Result as FmtResult},
marker::PhantomData,
ptr::{NonNull, null_mut},
};
use jl_sys::{
jl_alloc_svec, jl_alloc_svec_uninit, jl_emptysvec, jl_simplevector_type, jl_svec_copy,
jl_svec_t,
};
use jlrs_sys::{jlrs_svec_data, jlrs_svec_len, jlrs_svecref, jlrs_svecset};
use super::{AtomicSlice, Managed, ManagedData, Weak, datatype::DataType, private::ManagedPriv};
use crate::{
data::{
layout::valid_layout::{ValidField, ValidLayout},
managed::value::Value,
types::typecheck::Typecheck,
},
error::{AccessError, JlrsResult},
memory::target::{Target, TargetResult, unrooted::Unrooted},
prelude::LocalScopeExt,
private::Private,
};
#[repr(transparent)]
pub struct SimpleVectorAccessor<'borrow, T = Value<'borrow, 'static>>(
SimpleVector<'borrow>,
PhantomData<&'borrow AtomicSlice<'borrow, 'static, T, SimpleVector<'borrow>>>,
)
where
T: Managed<'borrow, 'static>;
impl<'borrow, T> SimpleVectorAccessor<'borrow, T>
where
T: Managed<'borrow, 'static>,
{
#[inline]
pub fn len(&self) -> usize {
unsafe { jlrs_svec_len(self.0.unwrap(Private)) }
}
pub fn get<'target, Tgt>(
&self,
target: Tgt,
index: usize,
) -> Option<ManagedData<'target, 'static, Tgt, T::InScope<'target>>>
where
Tgt: Target<'target>,
{
if index >= self.len() {
return None;
}
unsafe {
let v = jlrs_svecref(self.0.unwrap(Private).cast(), index);
if v.is_null() {
None
} else {
let v = Value::wrap_non_null(NonNull::new_unchecked(v), Private)
.cast_unchecked::<T>()
.root(target);
Some(v)
}
}
}
pub unsafe fn set(&self, index: usize, value: Option<T::InScope<'_>>) -> JlrsResult<()> {
unsafe {
if index >= self.len() {
Err(AccessError::OutOfBoundsSVec {
idx: index,
len: self.len(),
})?
}
let v = match value {
Some(v) => v.unwrap(Private).cast(),
None => null_mut(),
};
jlrs_svecset(self.0.unwrap(Private).cast(), index as _, v);
Ok(())
}
}
#[inline]
pub fn as_atomic_slice<'b>(
&'b self,
) -> AtomicSlice<'b, 'static, T::InScope<'b>, SimpleVector<'b>> {
let slice = unsafe {
let data = jlrs_svec_data(self.0.unwrap(Private)).cast();
std::slice::from_raw_parts(data, self.len())
};
AtomicSlice::new(self.0, slice)
}
}
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct SimpleVector<'scope>(NonNull<jl_svec_t>, PhantomData<&'scope ()>);
impl<'scope> SimpleVector<'scope> {
pub fn new<'elem, Tgt, T>(target: Tgt, elems: &[T]) -> SimpleVectorData<'scope, Tgt>
where
Tgt: Target<'scope>,
T: Managed<'elem, 'static>,
{
target.with_local_scope::<_, 1>(|target, mut frame| unsafe {
let svec = SimpleVector::with_capacity_uninit(&mut frame, elems.len());
{
let data = svec.data();
for (idx, elem) in elems.iter().copied().enumerate() {
data.set(idx, Some(elem.as_value())).unwrap();
}
}
svec.root(target)
})
}
#[inline]
pub fn with_capacity<Tgt>(target: Tgt, n: usize) -> SimpleVectorData<'scope, Tgt>
where
Tgt: Target<'scope>,
{
unsafe {
let svec = NonNull::new_unchecked(jl_alloc_svec(n));
target.data_from_ptr(svec, Private)
}
}
#[inline]
pub unsafe fn with_capacity_uninit<Tgt>(target: Tgt, n: usize) -> SimpleVectorData<'scope, Tgt>
where
Tgt: Target<'scope>,
{
unsafe {
let svec = NonNull::new_unchecked(jl_alloc_svec_uninit(n));
target.data_from_ptr(svec, Private)
}
}
#[inline]
pub fn copy<'target, Tgt>(self, target: Tgt) -> SimpleVectorData<'target, Tgt>
where
Tgt: Target<'target>,
{
unsafe {
let svec = jl_svec_copy(self.unwrap(Private));
let svec = SimpleVector::wrap_non_null(NonNull::new_unchecked(svec), Private);
svec.root(target)
}
}
#[inline]
pub fn data<'borrow>(&'borrow self) -> SimpleVectorAccessor<'borrow> {
SimpleVectorAccessor(*self, PhantomData)
}
#[inline]
pub unsafe fn typed_data_unchecked<'borrow, U>(
&'borrow self,
) -> SimpleVectorAccessor<'borrow, U>
where
U: Managed<'borrow, 'static>,
{
SimpleVectorAccessor(*self, PhantomData)
}
#[inline]
pub fn len(&self) -> usize {
unsafe { jlrs_svec_len(self.0.as_ptr()) }
}
}
impl<'base> SimpleVector<'base> {
#[inline]
pub fn emptysvec<Tgt: Target<'base>>(_: &Tgt) -> Self {
unsafe { Self::wrap_non_null(NonNull::new_unchecked(jl_emptysvec), Private) }
}
}
unsafe impl<'scope> Typecheck for SimpleVector<'scope> {
#[inline]
fn typecheck(t: DataType) -> bool {
let unrooted = unsafe { Unrooted::new() };
t == DataType::simplevector_type(&unrooted)
}
}
impl<'scope> Debug for SimpleVector<'scope> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let s = self
.display_string()
.unwrap_or(String::from("<Cannot display value>"));
write!(f, "{}", s)
}
}
impl<'scope> ManagedPriv<'scope, '_> for SimpleVector<'scope> {
type Wraps = jl_svec_t;
type WithLifetimes<'target, 'da> = SimpleVector<'target>;
const NAME: &'static str = "SimpleVector";
#[inline]
unsafe fn wrap_non_null(inner: NonNull<Self::Wraps>, _: Private) -> Self {
Self(inner, PhantomData)
}
#[inline]
fn unwrap_non_null(self, _: Private) -> NonNull<Self::Wraps> {
self.0
}
}
impl_construct_type_managed!(SimpleVector, 1, jl_simplevector_type);
pub type WeakSimpleVector<'scope> = Weak<'scope, 'static, SimpleVector<'scope>>;
pub type SimpleVectorRet = WeakSimpleVector<'static>;
unsafe impl<'scope> ValidLayout for WeakSimpleVector<'scope> {
#[inline]
fn valid_layout(v: Value) -> bool {
if v.is::<DataType>() {
let dt = unsafe { v.cast_unchecked::<DataType>() };
dt.is::<SimpleVector>()
} else {
false
}
}
#[inline]
fn type_object<'target, Tgt: Target<'target>>(target: &Tgt) -> Value<'target, 'static> {
DataType::simplevector_type(target).as_value()
}
const IS_REF: bool = true;
}
unsafe impl<'scope> ValidField for Option<WeakSimpleVector<'scope>> {
#[inline]
fn valid_field(v: Value) -> bool {
if v.is::<DataType>() {
let dt = unsafe { v.cast_unchecked::<DataType>() };
dt.is::<SimpleVector>()
} else {
false
}
}
}
use crate::memory::target::TargetType;
pub type SimpleVectorData<'target, Tgt> =
<Tgt as TargetType<'target>>::Data<'static, SimpleVector<'target>>;
pub type SimpleVectorResult<'target, Tgt> =
TargetResult<'target, 'static, SimpleVector<'target>, Tgt>;
impl_ccall_arg_managed!(SimpleVector, 1);
impl_into_typed!(SimpleVector);