1use core::ops::{Deref, DerefMut};
8use rustmex_core::{
9 convert::{
10 FromMatlabError,
11 },
12 mxArray,
13 classid::ClassID,
14 pointers::{
15 MatlabPtr,
16 MutMatlabPtr,
17 MxArray,
18 },
19 shim::{
20 rustmex_call_matlab as mexCallMATLAB,
21 },
22
23 MatlabClass,
24 MutMatlabClass,
25 OwnedMatlabClass,
26};
27
28use std::{
29 ffi::{
30 CString,
31 CStr,
32 }
33};
34
35pub fn call_named<FnName>(f: FnName, nargout: usize, rhs: &[&mxArray])
43 -> Result<Box<[Option<MxArray>]>, FunctionCallError>
44where
45 FnName: Into<Vec<u8>>,
46{
47 let f = CString::new(f).map_err(|_| FunctionCallError::BadEncoding)?;
48 call_named_nul(&f, nargout, rhs).ok_or(FunctionCallError::CallFailed)
49}
50
51pub fn call_named_nul(f: &CStr, nargout: usize, rhs: &[&mxArray])
55 -> Option<Box<[Option<MxArray>]>>
56{
57 let lhs = vec![None; nargout].into_boxed_slice();
58
59 let ret = unsafe {
60 mexCallMATLAB(
61 lhs.len().try_into().expect("Don't expect 4 billion return values"),
62 lhs.as_ptr() as *mut *mut mxArray,
63 rhs.len().try_into().expect("Don't expect 4 billion arguments"),
64 rhs.as_ptr() as *mut *mut mxArray,
65 f.as_ptr() as *const i8
66 )
67 };
68
69 if ret == 0 {
70 Some(lhs)
71 } else {
72 None
73 }
74}
75
76
77#[repr(transparent)]
84#[derive(Debug)]
85pub struct Function<F: MatlabPtr>(F);
86
87#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
88pub enum FunctionCallError {
89 BadEncoding,
90 CallFailed,
91}
92
93impl<P> Deref for Function<P> where P: MatlabPtr {
94 type Target = mxArray;
95
96 fn deref(&self) -> &Self::Target {
97 &self.0
98 }
99}
100
101impl<P> DerefMut for Function<P> where P: MutMatlabPtr {
102 fn deref_mut(&mut self) -> &mut Self::Target {
103 &mut self.0
104 }
105}
106
107
108const FEVAL: &[u8; 6] = b"feval\0";
110
111impl<F> Function<F> where F: MatlabPtr + AsRef<mxArray> {
112 pub fn call(&self, nargout: usize, rhs: &[&mxArray])
118 -> Option<Box<[Option<MxArray>]>>
119 {
120 let rhs = {
123 let mut v = Vec::with_capacity(rhs.len() + 1);
124 v.push(self.0.as_ref());
125 v.extend(rhs.iter().map(|x| x.as_ref()));
126 v
127 };
128
129 call_named_nul(unsafe { CStr::from_bytes_with_nul_unchecked(FEVAL) },
131 nargout,
132 &rhs)
133 }
134}
135
136impl<P> MatlabClass<P> for Function<P> where P: MatlabPtr {
137 fn from_mx_array(mx: P) -> Result<Self, FromMatlabError<P>> {
138 if mx.numel() != 1 {
139 return Err(FromMatlabError::new_badsize(mx));
140 }
141
142 if mx.class_id() == Ok(ClassID::Function) {
143 Ok(Function(mx))
144 } else {
145 Err(FromMatlabError::new_badclass(mx))
146 }
147 }
148
149 fn into_inner(self) -> P {
150 self.0
151 }
152
153 fn inner(&self) -> &P {
154 &self.0
155 }
156
157 type Owned = Function<MxArray>;
158 fn duplicate(&self) -> Self::Owned {
159 Function(self.0.duplicate())
160 }
161}
162
163impl<P> MutMatlabClass<P> for Function<P> where P: MutMatlabPtr {
164 type AsBorrowed<'a> = Function<&'a mxArray> where Self: 'a;
165 fn as_borrowed<'a>(&'a self) -> Self::AsBorrowed<'a> {
166 Function(self.0.deref())
167 }
168
169 fn inner_mut(&mut self) -> &mut P {
170 &mut self.0
171 }
172}
173
174impl OwnedMatlabClass for Function<MxArray> {
175 type AsMutable<'a> = Function<&'a mut mxArray> where Self: 'a;
176 fn as_mutable<'a>(&'a mut self) -> Self::AsMutable<'a> {
177 Function(self.0.deref_mut())
178 }
179}