nixide/nixide/src/expr/values/function.rs

140 lines
3.5 KiB
Rust

use std::cell::RefCell;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::ptr::NonNull;
use std::rc::Rc;
use super::{NixValue, Value};
use crate::errors::ErrorContext;
use crate::stdext::SliceExt;
use crate::sys;
use crate::util::wrappers::AsInnerPtr;
use crate::util::{panic_issue_call_failed, wrap};
pub struct NixFunction {
inner: NonNull<sys::NixValue>,
state: Rc<RefCell<NonNull<sys::EvalState>>>,
}
impl Clone for NixFunction {
fn clone(&self) -> Self {
let inner = self.inner.clone();
wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_value_incref(ctx.as_ptr(), self.as_ptr());
})
.unwrap();
Self {
inner,
state: self.state.clone(),
}
}
}
impl Drop for NixFunction {
fn drop(&mut self) {
let ctx = ErrorContext::new();
unsafe {
sys::nix_value_decref(ctx.as_ptr(), self.as_ptr());
}
}
}
impl Display for NixFunction {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "<function>")
}
}
impl Debug for NixFunction {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "NixFunction")
}
}
impl AsInnerPtr<sys::NixValue> for NixFunction {
#[inline]
unsafe fn as_ptr(&self) -> *mut sys::NixValue {
self.inner.as_ptr()
}
#[inline]
unsafe fn as_ref(&self) -> &sys::NixValue {
unsafe { self.inner.as_ref() }
}
#[inline]
unsafe fn as_mut(&mut self) -> &mut sys::NixValue {
unsafe { self.inner.as_mut() }
}
}
impl NixValue for NixFunction {
#[inline]
fn type_id(&self) -> sys::ValueType {
sys::ValueType::Function
}
fn from(inner: NonNull<sys::NixValue>, state: Rc<RefCell<NonNull<sys::EvalState>>>) -> Self {
Self { inner, state }
}
}
impl NixFunction {
pub fn call<T>(&self, arg: &T) -> Value
where
T: NixValue,
{
let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_alloc_value(ctx.as_ptr(), self.state.borrow().as_ptr())
})
.unwrap_or_else(|err| panic_issue_call_failed!("{}", err));
wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_value_call(
ctx.as_ptr(),
self.state.borrow().as_ptr(),
self.as_ptr(),
arg.as_ptr(),
inner.as_ptr(),
);
})
.unwrap_or_else(|err| panic_issue_call_failed!("{}", err));
Value::from((inner, self.state.clone()))
}
pub fn call_many<T>(&self, args: &[&T]) -> Value
where
T: NixValue,
{
let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_alloc_value(ctx.as_ptr(), self.state.borrow().as_ptr())
})
.unwrap_or_else(|err| panic_issue_call_failed!("{}", err));
wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_value_call_multi(
ctx.as_ptr(),
self.state.borrow().as_ptr(),
self.as_ptr(),
args.len(),
args.into_c_array(),
inner.as_ptr(),
);
})
.unwrap_or_else(|err| panic_issue_call_failed!("{}", err));
Value::from((inner, self.state.clone()))
}
}
// #[cfg(nightly)]
// impl<T> Fn<(&T,)> for NixFunction
// where
// T: NixValue,
// {
// extern "rust-call" fn call(&self, args: (&T,)) -> Value {
// self.call(args.0)
// }
// }