pub mod field_accessor;
pub mod tracked;
pub mod typed;
#[doc(hidden)]
#[macro_export]
macro_rules! count {
($name:expr_2021 => $value:expr_2021) => {
2
};
($name:expr_2021 => $value:expr_2021, $($rest:tt)+) => {
$crate::count!(2, $($rest)+)
};
($n:expr_2021, $name:expr_2021 => $value:expr_2021) => {
$n + 1
};
($n:expr_2021, $name:expr_2021 => $value:expr_2021, $($rest:tt)+) => {
$crate::count!($n + 1, $($rest)+)
};
}
use std::{
ffi::{CStr, CString, c_void},
marker::PhantomData,
mem::MaybeUninit,
ptr::NonNull,
usize,
};
use jl_sys::{
jl_an_empty_string, jl_an_empty_vec_any, jl_any_type, jl_apply_type, jl_array_any_type,
jl_array_int32_type, jl_array_symbol_type, jl_array_uint8_type, jl_bottom_type, jl_call,
jl_call0, jl_call1, jl_call2, jl_call3, jl_diverror_exception, jl_emptytuple, jl_eval_string,
jl_exception_occurred, jl_false, jl_field_index, jl_gc_add_finalizer, jl_gc_add_ptr_finalizer,
jl_get_nth_field, jl_get_nth_field_noalloc, jl_has_typevar, jl_interrupt_exception, jl_isa,
jl_memory_exception, jl_new_struct_uninit, jl_nothing, jl_object_id, jl_pair_type,
jl_readonlymemory_exception, jl_set_nth_field, jl_stackovf_exception, jl_static_show,
jl_stderr_obj, jl_stderr_stream, jl_stdout_stream, jl_subtype, jl_true, jl_typeof_str,
jl_undefref_exception, jl_value_t,
};
use jlrs_macros::julia_version;
use jlrs_sys::{jlrs_call_unchecked, jlrs_egal, jlrs_field_isptr};
use self::{field_accessor::FieldAccessor, typed::TypedValue};
use super::{Weak, type_var::TypeVar};
use crate::{
args::Values,
call::Call,
catch::{catch_exceptions, unwrap_exc},
convert::{into_julia::IntoJulia, to_symbol::ToSymbol, unbox::Unbox},
data::{
layout::{
is_bits::IsBits,
typed_layout::HasLayout,
valid_layout::{ValidField, ValidLayout},
},
managed::{
Managed,
datatype::DataType,
module::Module,
named_tuple::NamedTuple,
private::ManagedPriv,
symbol::Symbol,
union::Union,
union_all::UnionAll,
value::tracked::{Tracked, TrackedMut},
},
types::{construct_type::ConstructType, typecheck::Typecheck},
},
error::{AccessError, CANNOT_DISPLAY_TYPE, JlrsError, JlrsResult, TypeError},
memory::{
context::ledger::Ledger,
get_tls,
scope::LocalScopeExt,
target::{Target, TargetException, TargetResult, unrooted::Unrooted},
},
private::Private,
util::kwcall_function,
};
#[repr(transparent)]
#[derive(Copy, Clone, Eq)]
pub struct Value<'scope, 'data>(
NonNull<jl_value_t>,
PhantomData<&'scope ()>,
PhantomData<&'data mut ()>,
);
impl<'scope, 'data, T: Managed<'scope, 'data>> PartialEq<T> for Value<'_, '_> {
#[inline]
fn eq(&self, other: &T) -> bool {
self.egal(other.as_value())
}
}
unsafe impl Typecheck for Value<'_, '_> {
#[inline]
fn typecheck(_: DataType) -> bool {
true
}
}
impl Value<'_, '_> {
#[inline]
pub fn new<'target, V, Tgt>(target: Tgt, value: V) -> ValueData<'target, 'static, Tgt>
where
V: IntoJulia,
Tgt: Target<'target>,
{
value.into_julia(target)
}
pub fn new_bits<'target, T, Tgt>(target: Tgt, layout: T) -> ValueData<'target, 'static, Tgt>
where
T: ConstructType + ValidLayout + IsBits,
Tgt: Target<'target>,
{
unsafe {
let ty = T::construct_type(&target)
.as_value()
.cast_unchecked::<DataType>();
let val = NonNull::new_unchecked(jl_new_struct_uninit(ty.unwrap(Private)));
val.cast::<MaybeUninit<T>>().as_mut().write(layout);
target.data_from_ptr(val, Private)
}
}
pub fn new_bits_from_layout<'target, T, Tgt>(
target: Tgt,
layout: T::Layout,
) -> JlrsResult<ValueData<'target, 'static, Tgt>>
where
T: HasLayout<'target, 'static>,
T::Layout: IsBits,
Tgt: Target<'target>,
{
unsafe {
let ty = T::construct_type(&target).as_value().cast::<DataType>()?;
let val = NonNull::new_unchecked(jl_new_struct_uninit(ty.unwrap(Private)));
val.cast::<MaybeUninit<T::Layout>>().as_mut().write(layout);
Ok(target.data_from_ptr(val, Private))
}
}
pub fn new_bits_with_type<'target, T, L, Tgt>(
target: Tgt,
layout: L,
) -> JlrsResult<ValueData<'target, 'static, Tgt>>
where
T: ConstructType,
L: IsBits + ValidLayout,
Tgt: Target<'target>,
{
unsafe {
let ty = T::construct_type(&target).as_value();
if !L::valid_layout(ty) {
let value_type = ty.display_string_or(CANNOT_DISPLAY_TYPE);
Err(TypeError::InvalidLayout { value_type })?;
}
let ty = ty.cast_unchecked::<DataType>();
let val = NonNull::new_unchecked(jl_new_struct_uninit(ty.unwrap(Private)));
val.cast::<MaybeUninit<L>>().as_mut().write(layout);
Ok(target.data_from_ptr(val, Private))
}
}
pub unsafe fn try_new_with<'target, Ty, L, Tgt>(
target: Tgt,
layout: L,
) -> JlrsResult<ValueData<'target, 'static, Tgt>>
where
Ty: ConstructType,
L: ValidLayout,
Tgt: Target<'target>,
{
unsafe {
const {
let _: () = assert!(!L::IS_REF);
}
target.with_local_scope::<_, 1>(|target, mut frame| {
let ty = Ty::construct_type(&mut frame);
let ty_dt = ty.cast::<DataType>()?;
if !ty_dt.is_concrete_type() {
let value = ty.display_string_or(CANNOT_DISPLAY_TYPE);
Err(TypeError::NotConcrete { value })?;
}
if !L::valid_layout(ty) {
let value_type = ty.display_string_or(CANNOT_DISPLAY_TYPE);
Err(TypeError::InvalidLayout { value_type })?;
}
if let Some(n_fields) = ty_dt.n_fields() {
for i in 0..n_fields as usize {
let ft = ty_dt.field_type_unchecked(i);
if ty_dt.is_pointer_field_unchecked(i) {
let offset = ty_dt.field_offset_unchecked(i) as usize;
check_field_isa(ft, &layout, offset)?;
} else {
match ft.cast::<Union>() {
Ok(u) => {
check_union_equivalent::<L, _>(&frame, i, u)?;
}
_ => {}
}
}
}
}
let ptr = jl_new_struct_uninit(ty_dt.unwrap(Private));
std::ptr::write(ptr.cast::<L>(), layout);
Ok(target.data_from_ptr(NonNull::new_unchecked(ptr), Private))
})
}
}
pub fn apply_type<'target, 'value, 'data, V, Tgt>(
self,
target: Tgt,
types: V,
) -> ValueResult<'target, 'data, Tgt>
where
Tgt: Target<'target>,
V: AsRef<[Value<'value, 'data>]>,
{
unsafe {
let types = types.as_ref();
let callback =
|| jl_apply_type(self.unwrap(Private), types.as_ptr() as *mut _, types.len());
let res = match catch_exceptions(callback, unwrap_exc) {
Ok(ptr) => Ok(NonNull::new_unchecked(ptr)),
Err(e) => Err(e),
};
target.result_from_ptr(res, Private)
}
}
#[inline]
pub unsafe fn apply_type_unchecked<'target, 'value, 'data, Tgt, V>(
self,
target: Tgt,
types: V,
) -> ValueData<'target, 'data, Tgt>
where
Tgt: Target<'target>,
V: AsRef<[Value<'value, 'data>]>,
{
unsafe {
let types = types.as_ref();
let applied =
jl_apply_type(self.unwrap(Private), types.as_ptr() as *mut _, types.len());
target.data_from_ptr(NonNull::new_unchecked(applied), Private)
}
}
}
pub enum Stream {
Stdout,
Stderr,
}
impl Value<'_, '_> {
pub fn show(self, stream: Stream) -> usize {
unsafe {
let stream = match stream {
Stream::Stdout => jl_stdout_stream(),
Stream::Stderr => jl_stderr_stream(),
};
jl_static_show(stream, self.unwrap(Private))
}
}
}
impl<'scope, 'data> Value<'scope, 'data> {
#[inline]
pub fn datatype(self) -> DataType<'scope> {
unsafe {
let self_ptr = self.unwrap(Private);
let ty = jlrs_sys::jlrs_typeof(self_ptr);
DataType::wrap_non_null(NonNull::new_unchecked(ty.cast()), Private)
}
}
#[inline]
pub fn datatype_name(self) -> &'scope str {
unsafe {
let type_name = jl_typeof_str(self.unwrap(Private));
let type_name_ref = CStr::from_ptr(type_name);
type_name_ref.to_str().unwrap()
}
}
pub fn depends_on(&self, tvar: TypeVar) -> bool {
unsafe {
if self.is::<DataType>() {
let dt = self.cast_unchecked::<DataType>();
dt.depends_on(tvar)
} else if self.is::<UnionAll>() {
let ua = self.cast_unchecked::<UnionAll>();
ua.depends_on(tvar)
} else if self.is::<Union>() {
let u = self.cast_unchecked::<Union>();
u.depends_on(tvar)
} else if self.is::<TypeVar>() {
let tv = self.cast_unchecked::<TypeVar>();
tv.depends_on(tvar)
} else {
false
}
}
}
}
impl Value<'_, '_> {
#[inline]
pub fn is<T: Typecheck>(self) -> bool {
self.datatype().is::<T>()
}
#[inline]
pub fn subtype(self, sup: Value) -> bool {
unsafe { jl_subtype(self.unwrap(Private), sup.unwrap(Private)) != 0 }
}
#[inline]
pub fn is_kind(self) -> bool {
let global = unsafe { Unrooted::new() };
let ptr = self.unwrap(Private);
ptr == DataType::datatype_type(&global).unwrap(Private).cast()
|| ptr == DataType::unionall_type(&global).unwrap(Private).cast()
|| ptr == DataType::uniontype_type(&global).unwrap(Private).cast()
|| ptr == DataType::typeofbottom_type(&global).unwrap(Private).cast()
}
#[inline]
pub fn is_type(self) -> bool {
Value::is_kind(self.datatype().as_value())
}
#[inline]
pub fn isa(self, ty: Value) -> bool {
unsafe { jl_isa(self.unwrap(Private), ty.unwrap(Private)) != 0 }
}
pub fn has_typevar(self, tvar: TypeVar) -> bool {
unsafe { jl_has_typevar(self.unwrap(Private), tvar.unwrap(Private)) != 0 }
}
}
impl<'scope, 'data> Value<'scope, 'data> {
#[inline]
pub fn track_shared<'borrow, T: ValidLayout>(
&'borrow self,
) -> JlrsResult<Tracked<'borrow, 'scope, 'data, T>> {
let ty = self.datatype();
if !T::valid_layout(ty.as_value()) {
let value_type = ty.display_string_or(CANNOT_DISPLAY_TYPE).into();
Err(AccessError::InvalidLayout { value_type })?;
}
if !ty.mutable() {
unsafe {
return Ok(Tracked::new(self));
}
}
unsafe {
Ledger::try_borrow_shared(*self)?;
Ok(Tracked::new(self))
}
}
#[inline]
pub unsafe fn track_exclusive<'borrow, T: ValidLayout>(
&'borrow mut self,
) -> JlrsResult<TrackedMut<'borrow, 'scope, 'data, T>> {
unsafe {
let ty = self.datatype();
if !ty.mutable() {
let value_type = ty.display_string_or(CANNOT_DISPLAY_TYPE).into();
Err(TypeError::Immutable { value_type })?;
}
if !T::valid_layout(ty.as_value()) {
let value_type = ty.display_string_or(CANNOT_DISPLAY_TYPE).into();
Err(AccessError::InvalidLayout { value_type })?;
}
Ledger::try_borrow_exclusive(*self)?;
Ok(TrackedMut::new(self))
}
}
#[inline]
pub fn is_tracked(self) -> JlrsResult<bool> {
Ledger::is_borrowed(self)
}
#[inline]
pub fn is_tracked_shared(self) -> JlrsResult<bool> {
Ledger::is_borrowed_shared(self)
}
#[inline]
pub fn is_tracked_exclusive(self) -> JlrsResult<bool> {
Ledger::is_borrowed_exclusive(self)
}
}
impl ValueUnbound {
#[inline]
pub unsafe fn track_shared_unbound<T: ValidLayout + Send>(
self,
) -> JlrsResult<Tracked<'static, 'static, 'static, T>> {
let ty = self.datatype();
if !T::valid_layout(ty.as_value()) {
let value_type = ty.display_string_or(CANNOT_DISPLAY_TYPE).into();
Err(AccessError::InvalidLayout { value_type })?;
}
unsafe {
Ledger::try_borrow_shared(self)?;
Ok(Tracked::new_owned(self))
}
}
#[inline]
pub unsafe fn track_exclusive_unbound<T: ValidLayout + Send>(
self,
) -> JlrsResult<TrackedMut<'static, 'static, 'static, T>> {
unsafe {
let ty = self.datatype();
if !ty.mutable() {
let value_type = ty.display_string_or(CANNOT_DISPLAY_TYPE).into();
Err(TypeError::Immutable { value_type })?;
}
if !T::valid_layout(ty.as_value()) {
let value_type = ty.display_string_or(CANNOT_DISPLAY_TYPE).into();
Err(AccessError::InvalidLayout { value_type })?;
}
Ledger::try_borrow_exclusive(self)?;
Ok(TrackedMut::new_owned(self))
}
}
}
impl<'scope, 'data> Value<'scope, 'data> {
#[inline]
pub unsafe fn assume_owned(self) -> Value<'scope, 'static> {
unsafe { Value::wrap_non_null(self.unwrap_non_null(Private), Private) }
}
}
impl<'scope, 'data> Value<'scope, 'data> {
#[inline]
pub fn cast<T: Managed<'scope, 'data> + Typecheck>(self) -> JlrsResult<T> {
if self.is::<T>() {
unsafe { Ok(self.cast_unchecked()) }
} else {
Err(AccessError::InvalidLayout {
value_type: self.datatype().display_string_or(CANNOT_DISPLAY_TYPE),
})?
}
}
#[inline]
pub unsafe fn cast_unchecked<T: Managed<'scope, 'data>>(self) -> T {
unsafe { T::from_value_unchecked(self, Private) }
}
#[inline]
pub fn unbox<T: Unbox + Typecheck>(self) -> JlrsResult<T::Output> {
if !self.is::<T>() {
Err(AccessError::InvalidLayout {
value_type: self.datatype().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
unsafe { Ok(T::unbox(self)) }
}
#[inline]
pub unsafe fn unbox_unchecked<T: Unbox>(self) -> T::Output {
unsafe { T::unbox(self) }
}
pub fn as_typed<'target, T: ConstructType, Tgt: Target<'target>>(
self,
target: &Tgt,
) -> JlrsResult<TypedValue<'scope, 'data, T>> {
target.with_local_scope::<_, 1>(|_, mut frame| {
let ty = T::construct_type(&mut frame);
if self.isa(ty) {
unsafe { Ok(TypedValue::<T>::from_value_unchecked(self)) }
} else {
Err(TypeError::NotA {
value: self.display_string_or("<Cannot display value>"),
field_type: ty.display_string_or("<Cannot display type>"),
})?
}
})
}
#[inline]
pub unsafe fn as_typed_unchecked<T: ConstructType>(self) -> TypedValue<'scope, 'data, T> {
unsafe { TypedValue::<T>::from_value_unchecked(self) }
}
#[inline]
pub fn data_ptr(self) -> NonNull<c_void> {
self.unwrap_non_null(Private).cast()
}
}
impl<'scope, 'data> Value<'scope, 'data> {
#[inline]
pub fn field_names(self) -> &'scope [Symbol<'scope>] {
unsafe {
std::mem::transmute(
self.datatype()
.field_names()
.data()
.as_atomic_slice()
.assume_immutable_non_null(),
)
}
}
#[inline]
pub fn n_fields(self) -> usize {
self.datatype().n_fields().unwrap() as _
}
#[inline]
pub fn field_accessor(self) -> FieldAccessor<'scope, 'data> {
FieldAccessor::new(self)
}
pub fn get_nth_field<'target, Tgt>(
self,
target: Tgt,
idx: usize,
) -> JlrsResult<ValueData<'target, 'data, Tgt>>
where
Tgt: Target<'target>,
{
if idx >= self.n_fields() {
Err(AccessError::OutOfBoundsField {
idx,
n_fields: self.n_fields(),
value_type: self.datatype().display_string_or(CANNOT_DISPLAY_TYPE),
})?
}
if self.is::<Module>() {
Err(AccessError::ModuleField)?
}
unsafe {
let fld_ptr = jl_get_nth_field(self.unwrap(Private), idx as _);
if fld_ptr.is_null() {
Err(AccessError::UndefRef)?;
}
Ok(target.data_from_ptr(NonNull::new_unchecked(fld_ptr), Private))
}
}
pub fn get_nth_field_ref(self, idx: usize) -> JlrsResult<WeakValue<'scope, 'data>> {
let ty = self.datatype();
if idx >= ty.n_fields().unwrap() as _ {
Err(AccessError::OutOfBoundsField {
idx,
n_fields: self.n_fields(),
value_type: self.datatype().display_string_or(CANNOT_DISPLAY_TYPE),
})?
}
if self.is::<Module>() {
Err(AccessError::ModuleField)?
}
unsafe {
if jlrs_field_isptr(ty.unwrap(Private), idx as _) == 0 {
let value_type = ty.display_string_or(CANNOT_DISPLAY_TYPE);
let field_name = if let Some(field_name) = self.field_names().get(idx) {
field_name
.as_str()
.unwrap_or("<Cannot display field name>")
.to_string()
} else {
format!("{}", idx)
};
Err(AccessError::NotAPointerField {
value_type: value_type,
field_name,
})?
}
Ok(WeakValue::wrap(NonNull::new_unchecked(
jl_get_nth_field_noalloc(self.unwrap(Private), idx),
)))
}
}
pub fn get_field<'target, N, Tgt>(
self,
target: Tgt,
field_name: N,
) -> JlrsResult<ValueData<'target, 'data, Tgt>>
where
N: ToSymbol,
Tgt: Target<'target>,
{
if self.is::<Module>() {
Err(AccessError::ModuleField)?
}
unsafe {
let symbol = field_name.to_symbol_priv(Private);
let idx = jl_field_index(self.datatype().unwrap(Private), symbol.unwrap(Private), 0);
if idx < 0 {
Err(AccessError::NoSuchField {
type_name: self.datatype().display_string_or(CANNOT_DISPLAY_TYPE),
field_name: symbol.as_str().unwrap_or("<Non-UTF8 symbol>").into(),
})?
}
let fld_ptr = jl_get_nth_field(self.unwrap(Private), idx as _);
if fld_ptr.is_null() {
Err(AccessError::UndefRef)?;
}
Ok(target.data_from_ptr(NonNull::new_unchecked(fld_ptr), Private))
}
}
pub fn get_field_ref<N>(self, field_name: N) -> JlrsResult<Option<WeakValue<'scope, 'data>>>
where
N: ToSymbol,
{
if self.is::<Module>() {
Err(AccessError::ModuleField)?
}
unsafe {
let symbol = field_name.to_symbol_priv(Private);
let ty = self.datatype();
let idx = jl_field_index(ty.unwrap(Private), symbol.unwrap(Private), 0);
if idx < 0 {
Err(AccessError::NoSuchField {
type_name: ty.display_string_or(CANNOT_DISPLAY_TYPE),
field_name: symbol.as_str().unwrap_or("<Non-UTF8 symbol>").into(),
})?
}
if jlrs_field_isptr(ty.unwrap(Private), idx as _) == 0 {
let idx = idx as usize;
let value_type = ty.display_string_or(CANNOT_DISPLAY_TYPE);
let field_name = self.field_names()[idx]
.as_str()
.unwrap_or("<Cannot display field name>")
.to_string();
Err(AccessError::NotAPointerField {
value_type: value_type,
field_name,
})?
}
let ptr = jl_get_nth_field_noalloc(self.unwrap(Private), idx as _);
if ptr.is_null() {
Ok(None)
} else {
Ok(Some(WeakValue::wrap(NonNull::new_unchecked(ptr))))
}
}
}
pub unsafe fn set_nth_field<'target, Tgt>(
self,
target: Tgt,
idx: usize,
value: Value<'_, 'data>,
) -> JlrsResult<TargetException<'target, 'data, (), Tgt>>
where
Tgt: Target<'target>,
{
unsafe {
if self.is::<Module>() {
Err(AccessError::ModuleField)?
}
let n_fields = self.n_fields();
if n_fields <= idx {
Err(AccessError::OutOfBoundsField {
idx,
n_fields,
value_type: self.datatype().display_string_or(CANNOT_DISPLAY_TYPE),
})?;
}
let field_type = self
.datatype()
.field_types()
.data()
.get(&target, idx)
.unwrap()
.as_value();
let dt = value.datatype();
if !Value::subtype(dt.as_value(), field_type) {
Err(TypeError::NotASubtype {
field_type: field_type.display_string_or(CANNOT_DISPLAY_TYPE),
value_type: value.datatype().display_string_or(CANNOT_DISPLAY_TYPE),
})?
}
let callback = || jl_set_nth_field(self.unwrap(Private), idx, value.unwrap(Private));
let res = match catch_exceptions(callback, unwrap_exc) {
Ok(_) => Ok(()),
Err(e) => Err(e),
};
Ok(target.exception_from_ptr(res, Private))
}
}
#[inline]
pub unsafe fn set_nth_field_unchecked(self, idx: usize, value: Value<'_, 'data>) {
unsafe { jl_set_nth_field(self.unwrap(Private), idx, value.unwrap(Private)) }
}
pub unsafe fn set_field<'target, N, Tgt>(
self,
target: Tgt,
field_name: N,
value: Value<'_, 'data>,
) -> JlrsResult<TargetException<'target, 'data, (), Tgt>>
where
N: ToSymbol,
Tgt: Target<'target>,
{
unsafe {
if self.is::<Module>() {
Err(AccessError::ModuleField)?
}
let symbol = field_name.to_symbol_priv(Private);
let idx = jl_field_index(self.datatype().unwrap(Private), symbol.unwrap(Private), 0);
if idx < 0 {
Err(AccessError::NoSuchField {
type_name: self.datatype().display_string_or(CANNOT_DISPLAY_TYPE),
field_name: symbol.as_str().unwrap_or("<Non-UTF8 symbol>").into(),
})?
}
let field_type = self
.datatype()
.field_types()
.data()
.get(&target, idx as usize)
.unwrap()
.as_value();
let dt = value.datatype();
if !Value::subtype(dt.as_value(), field_type) {
Err(TypeError::NotASubtype {
field_type: field_type.display_string_or(CANNOT_DISPLAY_TYPE),
value_type: value.datatype().display_string_or(CANNOT_DISPLAY_TYPE),
})?
}
let callback =
|| jl_set_nth_field(self.unwrap(Private), idx as usize, value.unwrap(Private));
let res = match catch_exceptions(callback, unwrap_exc) {
Ok(_) => Ok(()),
Err(e) => Err(e),
};
Ok(target.exception_from_ptr(res, Private))
}
}
pub unsafe fn set_field_unchecked<N>(
self,
field_name: N,
value: Value<'_, 'data>,
) -> JlrsResult<()>
where
N: ToSymbol,
{
unsafe {
let symbol = field_name.to_symbol_priv(Private);
let idx = jl_field_index(self.datatype().unwrap(Private), symbol.unwrap(Private), 0);
if idx < 0 {
Err(AccessError::NoSuchField {
type_name: self.datatype().display_string_or(CANNOT_DISPLAY_TYPE),
field_name: symbol.as_str().unwrap_or("<Non-UTF8 symbol>").into(),
})?
}
Ok(jl_set_nth_field(
self.unwrap(Private),
idx as usize,
value.unwrap(Private),
))
}
}
}
impl Value<'_, '_> {
#[inline]
pub unsafe fn eval_string<'target, C, Tgt>(
target: Tgt,
cmd: C,
) -> ValueResult<'target, 'static, Tgt>
where
C: AsRef<str>,
Tgt: Target<'target>,
{
unsafe {
let cmd = cmd.as_ref();
let cmd_cstring = CString::new(cmd).map_err(JlrsError::other).unwrap();
let cmd_ptr = cmd_cstring.as_ptr();
let res = jl_eval_string(cmd_ptr);
let exc = jl_exception_occurred();
let output = if exc.is_null() {
Ok(NonNull::new_unchecked(res))
} else {
Err(NonNull::new_unchecked(exc))
};
target.result_from_ptr(output, Private)
}
}
#[inline]
pub unsafe fn eval_cstring<'target, C, Tgt>(
target: Tgt,
cmd: C,
) -> ValueResult<'target, 'static, Tgt>
where
C: AsRef<CStr>,
Tgt: Target<'target>,
{
unsafe {
let cmd = cmd.as_ref();
let cmd_ptr = cmd.as_ptr();
let res = jl_eval_string(cmd_ptr);
let exc = jl_exception_occurred();
let output = if exc.is_null() {
Ok(NonNull::new_unchecked(res))
} else {
Err(NonNull::new_unchecked(exc))
};
target.result_from_ptr(output, Private)
}
}
}
impl Value<'_, '_> {
#[inline]
pub fn object_id(self) -> usize {
unsafe { jl_object_id(self.unwrap(Private)) }
}
#[inline]
pub fn egal(self, other: Value) -> bool {
unsafe { jlrs_egal(self.unwrap(Private), other.unwrap(Private)) != 0 }
}
}
impl Value<'_, '_> {
#[inline]
pub unsafe fn add_finalizer(self, f: Value<'_, 'static>) {
unsafe { jl_gc_add_finalizer(self.unwrap(Private), f.unwrap(Private)) }
}
#[inline]
pub unsafe fn add_ptr_finalizer(self, f: unsafe extern "C" fn(*mut c_void) -> ()) {
unsafe { jl_gc_add_ptr_finalizer(get_tls(), self.unwrap(Private), f as *mut c_void) }
}
}
impl<'scope> Value<'scope, 'static> {
#[inline]
pub fn bottom_type<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_bottom_type), Private) }
}
#[inline]
pub fn stackovf_exception<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_stackovf_exception), Private) }
}
#[inline]
pub fn memory_exception<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_memory_exception), Private) }
}
#[inline]
pub fn readonlymemory_exception<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe {
Value::wrap_non_null(NonNull::new_unchecked(jl_readonlymemory_exception), Private)
}
}
#[inline]
pub fn diverror_exception<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_diverror_exception), Private) }
}
#[inline]
pub fn undefref_exception<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_undefref_exception), Private) }
}
#[inline]
pub fn interrupt_exception<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_interrupt_exception), Private) }
}
#[inline]
pub fn an_empty_vec_any<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_an_empty_vec_any), Private) }
}
#[inline]
pub fn an_empty_string<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_an_empty_string), Private) }
}
#[inline]
pub fn array_uint8_type<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_array_uint8_type), Private) }
}
#[inline]
pub fn array_any_type<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_array_any_type), Private) }
}
#[inline]
pub fn array_symbol_type<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_array_symbol_type), Private) }
}
#[inline]
pub fn array_int32_type<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_array_int32_type), Private) }
}
#[inline]
pub fn emptytuple<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_emptytuple), Private) }
}
#[inline]
pub fn true_v<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_true), Private) }
}
#[inline]
pub fn false_v<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_false), Private) }
}
#[inline]
pub fn nothing<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_nothing), Private) }
}
#[inline]
pub fn stderr<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_stderr_obj()), Private) }
}
#[inline]
pub fn pair_type<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe { Value::wrap_non_null(NonNull::new_unchecked(jl_pair_type), Private) }
}
#[julia_version(since = "1.11")]
#[inline]
pub fn an_empty_memory_any<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe {
Value::wrap_non_null(
NonNull::new_unchecked(jl_sys::jl_an_empty_memory_any),
Private,
)
}
}
#[inline]
pub fn array_uint64_type<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe {
Value::wrap_non_null(
NonNull::new_unchecked(jl_sys::jl_array_uint64_type),
Private,
)
}
}
#[julia_version(since = "1.11")]
#[inline]
pub fn array_uint32_type<Tgt>(_: &Tgt) -> Self
where
Tgt: Target<'scope>,
{
unsafe {
Value::wrap_non_null(
NonNull::new_unchecked(jl_sys::jl_array_uint32_type),
Private,
)
}
}
}
impl<'data> Call<'data> for Value<'_, 'data> {
#[inline]
unsafe fn call_unchecked<'target, 'value, V, Tgt, const N: usize>(
self,
target: Tgt,
args: V,
) -> ValueData<'target, 'data, Tgt>
where
V: Values<'value, 'data, N>,
Tgt: Target<'target>,
{
unsafe {
let args = args.as_pointers(Private);
let v = jlrs_call_unchecked(
self.unwrap(Private),
args.as_ptr() as *mut _,
args.len() as _,
);
target.data_from_ptr(NonNull::new_unchecked(v), Private)
}
}
#[inline]
unsafe fn call<'target, 'value, V, Tgt, const N: usize>(
self,
target: Tgt,
args: V,
) -> ValueResult<'target, 'data, Tgt>
where
V: Values<'value, 'data, N>,
Tgt: Target<'target>,
{
unsafe {
let args = args.as_slice(Private);
let n = args.len();
let res = match N {
0 => jl_call0(self.unwrap(Private)),
1 => jl_call1(self.unwrap(Private), args[0].unwrap(Private)),
2 => jl_call2(
self.unwrap(Private),
args[0].unwrap(Private),
args[1].unwrap(Private),
),
3 => jl_call3(
self.unwrap(Private),
args[0].unwrap(Private),
args[1].unwrap(Private),
args[2].unwrap(Private),
),
usize::MAX => match n {
0 => jl_call0(self.unwrap(Private)),
1 => jl_call1(self.unwrap(Private), args[0].unwrap(Private)),
2 => jl_call2(
self.unwrap(Private),
args[0].unwrap(Private),
args[1].unwrap(Private),
),
3 => jl_call3(
self.unwrap(Private),
args[0].unwrap(Private),
args[1].unwrap(Private),
args[2].unwrap(Private),
),
_ => jl_call(
self.unwrap(Private),
args.as_ptr() as *const _ as *mut _,
n as _,
),
},
_ => jl_call(
self.unwrap(Private),
args.as_ptr() as *const _ as *mut _,
n as _,
),
};
let exc = jl_exception_occurred();
let res = if exc.is_null() {
Ok(NonNull::new_unchecked(res))
} else {
Err(NonNull::new_unchecked(exc))
};
target.result_from_ptr(res, Private)
}
}
unsafe fn call_kw<'target, 'value, V, Tgt, const N: usize>(
self,
target: Tgt,
args: V,
kwargs: NamedTuple<'_, 'data>,
) -> ValueResult<'target, 'data, Tgt>
where
V: Values<'value, 'data, N>,
Tgt: Target<'target>,
{
unsafe {
let func = kwcall_function(&target);
let values = args.into_extended_pointers_with_start(
[kwargs.unwrap(Private), self.unwrap(Private)],
Private,
);
let values = values.as_ref();
let res = jl_call(func, values.as_ptr() as *mut _, values.len() as _);
let exc = jl_exception_occurred();
let res = if exc.is_null() {
Ok(NonNull::new_unchecked(res))
} else {
Err(NonNull::new_unchecked(exc))
};
target.result_from_ptr(res, Private)
}
}
}
#[allow(deprecated)]
impl<'value, 'data> crate::call::ProvideKeywords<'value, 'data> for Value<'value, 'data> {
#[inline]
#[allow(deprecated)]
fn provide_keywords(
self,
kws: NamedTuple<'value, 'data>,
) -> crate::call::WithKeywords<'value, 'data> {
crate::call::WithKeywords::new(self, kws)
}
}
impl_debug!(Value<'_, '_>);
impl<'scope, 'data> ManagedPriv<'scope, 'data> for Value<'scope, 'data> {
type Wraps = jl_value_t;
type WithLifetimes<'target, 'da> = Value<'target, 'da>;
const NAME: &'static str = "Value";
#[inline]
unsafe fn wrap_non_null(inner: NonNull<Self::Wraps>, _: Private) -> Self {
Self(inner, PhantomData, PhantomData)
}
#[inline]
fn unwrap_non_null(self, _: Private) -> NonNull<Self::Wraps> {
self.0
}
}
pub type WeakValue<'scope, 'data> = Weak<'scope, 'data, Value<'scope, 'data>>;
pub type ValueRet = WeakValue<'static, 'static>;
pub type ValueUnbound = Value<'static, 'static>;
unsafe impl ValidLayout for WeakValue<'_, '_> {
#[inline]
fn valid_layout(v: Value) -> bool {
if v.is::<DataType>() {
let dt = unsafe { v.cast_unchecked::<DataType>() };
!dt.is_inline_alloc()
} else if v.is::<UnionAll>() {
true
} else if v.is::<Union>() {
let u = unsafe { v.cast_unchecked::<Union>() };
!u.is_bits_union()
} else {
false
}
}
#[inline]
fn type_object<'target, Tgt: Target<'target>>(target: &Tgt) -> Value<'target, 'static> {
DataType::any_type(target).as_value()
}
const IS_REF: bool = true;
}
unsafe impl ValidLayout for Value<'static, 'static> {
#[inline]
fn valid_layout(v: Value) -> bool {
if v.is::<DataType>() {
let dt = unsafe { v.cast_unchecked::<DataType>() };
!dt.is_inline_alloc()
} else if v.is::<UnionAll>() {
true
} else if v.is::<Union>() {
let u = unsafe { v.cast_unchecked::<Union>() };
!u.is_bits_union()
} else {
false
}
}
#[inline]
fn type_object<'target, Tgt: Target<'target>>(target: &Tgt) -> Value<'target, 'static> {
DataType::any_type(target).as_value()
}
const IS_REF: bool = true;
}
unsafe impl ValidField for Option<WeakValue<'_, '_>> {
#[inline]
fn valid_field(v: Value) -> bool {
if v.is::<DataType>() {
let dt = unsafe { v.cast_unchecked::<DataType>() };
!dt.is_inline_alloc()
} else if v.is::<UnionAll>() {
true
} else if v.is::<Union>() {
let u = unsafe { v.cast_unchecked::<Union>() };
!u.is_bits_union()
} else {
false
}
}
}
use crate::memory::target::TargetType;
pub type ValueData<'target, 'data, Tgt> =
<Tgt as TargetType<'target>>::Data<'data, Value<'target, 'data>>;
pub type ValueResult<'target, 'data, Tgt> =
TargetResult<'target, 'data, Value<'target, 'data>, Tgt>;
impl_ccall_arg_managed!(Value, 2);
impl_construct_type_managed!(Value, 2, jl_any_type);
unsafe fn check_union_equivalent<'target, L: ValidLayout, Tgt: Target<'target>>(
target: &Tgt,
idx: usize,
u: Union,
) -> JlrsResult<()> {
unsafe {
let type_obj = L::type_object(target);
match type_obj.cast::<DataType>() {
Ok(type_obj) => {
let ft_in_layout = type_obj.field_type_unchecked(idx);
if ft_in_layout != u {
Err(TypeError::IncompatibleType {
element_type: u.display_string_or(CANNOT_DISPLAY_TYPE),
value_type: ft_in_layout.display_string_or(CANNOT_DISPLAY_TYPE),
})?
}
}
_ => match type_obj.cast::<UnionAll>() {
Ok(type_obj) => {
let base_type_obj = type_obj.base_type();
let ft_in_layout = base_type_obj.field_type_unchecked(idx);
if ft_in_layout != u {
Err(TypeError::IncompatibleType {
element_type: u.display_string_or(CANNOT_DISPLAY_TYPE),
value_type: ft_in_layout.display_string_or(CANNOT_DISPLAY_TYPE),
})?
}
}
_ => Err(TypeError::NotA {
value: type_obj.display_string_or(CANNOT_DISPLAY_TYPE),
field_type: "DataType or UnionAll".into(),
})?,
},
}
Ok(())
}
}
unsafe fn check_field_isa<L: ValidLayout>(ft: Value, data: &L, offset: usize) -> JlrsResult<()> {
unsafe {
if let Some(field) = (data as *const L)
.cast::<MaybeUninit<u8>>()
.add(offset)
.cast::<Value>()
.as_ref()
{
if !field.isa(ft) {
Err(TypeError::NotA {
value: field.display_string_or("<Cannot display value>"),
field_type: ft.display_string_or("<Cannot display type>"),
})?
}
}
Ok(())
}
}