use std::{marker::PhantomData, ptr::NonNull};
use jl_sys::{jl_expr_t, jl_expr_type};
use jlrs_sys::{jlrs_expr_head, jlrs_expr_nargs, jlrs_exprarg, jlrs_exprargset};
use super::{
Managed,
value::{Value, ValueData},
};
use crate::{
data::managed::{Weak, private::ManagedPriv, symbol::Symbol},
impl_julia_typecheck,
memory::target::{TargetResult, TargetType},
prelude::Target,
private::Private,
};
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct Expr<'scope>(NonNull<jl_expr_t>, PhantomData<&'scope ()>);
impl<'scope> Expr<'scope> {
pub fn head(self) -> Option<Symbol<'scope>> {
unsafe {
let head = jlrs_expr_head(self.unwrap(Private));
let head = NonNull::new(head)?;
Some(Symbol::wrap_non_null(head, Private))
}
}
pub fn n_args(self) -> usize {
unsafe { jlrs_expr_nargs(self.unwrap(Private)) }
}
pub fn arg<'target, Tgt>(
self,
target: Tgt,
index: usize,
) -> Option<ValueData<'target, 'static, Tgt>>
where
Tgt: Target<'target>,
{
unsafe {
let n_args = self.n_args();
if index >= n_args {
return None;
}
let arg = jlrs_exprarg(self.unwrap(Private), index);
let arg = NonNull::new(arg)?;
Some(Value::wrap_non_null(arg, Private).root(target))
}
}
pub unsafe fn set_arg(self, index: usize, data: Option<Value<'_, 'static>>) {
unsafe { jlrs_exprargset(self.unwrap(Private), index, std::mem::transmute(data)) }
}
}
impl_julia_typecheck!(Expr<'scope>, jl_expr_type, 'scope);
impl_debug!(Expr<'_>);
impl<'scope> ManagedPriv<'scope, '_> for Expr<'scope> {
type Wraps = jl_expr_t;
type WithLifetimes<'target, 'da> = Expr<'target>;
const NAME: &'static str = "Expr";
#[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!(Expr, 1, jl_expr_type);
pub type WeakExpr<'scope> = Weak<'scope, 'static, Expr<'scope>>;
pub type ExprRet = WeakExpr<'static>;
impl_valid_layout!(WeakExpr, Expr, jl_expr_type);
pub type ExprData<'target, Tgt> = <Tgt as TargetType<'target>>::Data<'static, Expr<'target>>;
pub type ExprResult<'target, Tgt> = TargetResult<'target, 'static, Expr<'target>, Tgt>;
impl_ccall_arg_managed!(Expr, 1);
impl_into_typed!(Expr);