use core::ops::{Deref, DerefMut};
use rustmex_core::{
convert::{
FromMatlabError,
},
mxArray,
classid::ClassID,
pointers::{
MatlabPtr,
MutMatlabPtr,
MxArray,
},
shim::{
rustmex_call_matlab as mexCallMATLAB,
},
MatlabClass,
MutMatlabClass,
OwnedMatlabClass,
};
use std::{
ffi::{
CString,
CStr,
}
};
pub fn call_named<FnName>(f: FnName, nargout: usize, rhs: &[&mxArray])
-> Result<Box<[Option<MxArray>]>, FunctionCallError>
where
FnName: Into<Vec<u8>>,
{
let f = CString::new(f).map_err(|_| FunctionCallError::BadEncoding)?;
call_named_nul(&f, nargout, rhs).ok_or(FunctionCallError::CallFailed)
}
pub fn call_named_nul(f: &CStr, nargout: usize, rhs: &[&mxArray])
-> Option<Box<[Option<MxArray>]>>
{
let lhs = vec![None; nargout].into_boxed_slice();
let ret = unsafe {
mexCallMATLAB(
lhs.len().try_into().expect("Don't expect 4 billion return values"),
lhs.as_ptr() as *mut *mut mxArray,
rhs.len().try_into().expect("Don't expect 4 billion arguments"),
rhs.as_ptr() as *mut *mut mxArray,
f.as_ptr() as *const i8
)
};
if ret == 0 {
Some(lhs)
} else {
None
}
}
#[repr(transparent)]
#[derive(Debug)]
pub struct Function<F: MatlabPtr>(F);
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum FunctionCallError {
BadEncoding,
CallFailed,
}
impl<P> Deref for Function<P> where P: MatlabPtr {
type Target = mxArray;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<P> DerefMut for Function<P> where P: MutMatlabPtr {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
const FEVAL: &[u8; 6] = b"feval\0";
impl<F> Function<F> where F: MatlabPtr + AsRef<mxArray> {
pub fn call(&self, nargout: usize, rhs: &[&mxArray])
-> Option<Box<[Option<MxArray>]>>
{
let rhs = {
let mut v = Vec::with_capacity(rhs.len() + 1);
v.push(self.0.as_ref());
v.extend(rhs.iter().map(|x| x.as_ref()));
v
};
call_named_nul(unsafe { CStr::from_bytes_with_nul_unchecked(FEVAL) },
nargout,
&rhs)
}
}
impl<P> MatlabClass<P> for Function<P> where P: MatlabPtr {
fn from_mx_array(mx: P) -> Result<Self, FromMatlabError<P>> {
if mx.numel() != 1 {
return Err(FromMatlabError::new_badsize(mx));
}
if mx.class_id() == Ok(ClassID::Function) {
Ok(Function(mx))
} else {
Err(FromMatlabError::new_badclass(mx))
}
}
fn into_inner(self) -> P {
self.0
}
fn inner(&self) -> &P {
&self.0
}
type Owned = Function<MxArray>;
fn duplicate(&self) -> Self::Owned {
Function(self.0.duplicate())
}
}
impl<P> MutMatlabClass<P> for Function<P> where P: MutMatlabPtr {
type AsBorrowed<'a> = Function<&'a mxArray> where Self: 'a;
fn as_borrowed<'a>(&'a self) -> Self::AsBorrowed<'a> {
Function(self.0.deref())
}
fn inner_mut(&mut self) -> &mut P {
&mut self.0
}
}
impl OwnedMatlabClass for Function<MxArray> {
type AsMutable<'a> = Function<&'a mut mxArray> where Self: 'a;
fn as_mutable<'a>(&'a mut self) -> Self::AsMutable<'a> {
Function(self.0.deref_mut())
}
}