1use crate::errors::{Error, ErrorKind};
4use crate::Result;
5use std::convert::TryInto;
6use std::num::Wrapping;
7use sys::{mbool, mcomplex, mint, mreal, MArgument, MImage, MNumericArray, MSparseArray, MTensor};
8
9mod private {
10 pub trait Sealed {}
11}
12
13pub trait MType: private::Sealed + Sized {}
18
19macro_rules! impl_mtypes {
20 ($($t:ty),+) => {
21 $(
22 impl private::Sealed for $t {}
23 impl MType for $t {}
24 )+
25 };
26}
27
28impl_mtypes!(
29 mbool,
30 mint,
31 mreal,
32 mcomplex,
33 MTensor,
34 MSparseArray,
35 MNumericArray,
36 MImage
37);
38
39#[doc(hidden)]
41pub trait MTypeOrVoid: private::Sealed {}
42
43impl<T: MType> MTypeOrVoid for T {}
44impl private::Sealed for () {}
45impl MTypeOrVoid for () {}
46
47pub trait InputAdaptor: Sized {
51 type Input: MType;
53
54 fn mtype_try_from(input: Self::Input) -> Result<Self>;
56}
57
58pub trait OutputAdaptor: Sized {
62 type Output: MType;
64
65 fn try_into_mtype(self) -> Result<Self::Output>;
67}
68
69#[doc(hidden)]
76pub trait MArgumentGetter<T: MType>: Sized {
77 fn try_get_arg(arg: MArgument) -> Result<Self>;
79}
80
81#[doc(hidden)]
88pub trait MArgumentSetter<T: MTypeOrVoid>: Sized {
89 fn try_set_arg(self, arg: &MArgument) -> Result<()>;
91}
92
93impl MArgumentSetter<()> for () {
94 #[inline]
95 fn try_set_arg(self, _arg: &MArgument) -> Result<()> {
96 Ok(())
97 }
98}
99
100macro_rules! impl_argument_getter {
101 ($fd:ident: $t:ty) => {
102 impl<T: InputAdaptor<Input = $t>> MArgumentGetter<$t> for T {
103 #[inline]
104 fn try_get_arg(arg: MArgument) -> Result<Self> {
105 unsafe {
106 let ptr = arg.$fd;
107 if ptr.is_null() {
108 return Err(Error::from(ErrorKind::TypeError));
109 }
110 T::mtype_try_from(std::ptr::read(ptr))
111 }
112 }
113 }
114 };
115}
116
117macro_rules! impl_argument_setter {
118 ($fd:ident: $t:ty) => {
119 impl<T: OutputAdaptor<Output = $t>> MArgumentSetter<$t> for T {
120 #[inline]
121 fn try_set_arg(self, arg: &MArgument) -> Result<()> {
122 unsafe {
123 let ptr = arg.$fd;
124 if ptr.is_null() {
125 return Err(Error::from(ErrorKind::TypeError));
126 }
127 std::ptr::write(ptr, self.try_into_mtype()?);
128 }
129 Ok(())
130 }
131 }
132 };
133}
134
135macro_rules! impl_argument_getter_setter {
136 {$($fd:ident: $t:ty,)*} => {
137 $(
138 impl_argument_getter!($fd: $t);
139 impl_argument_setter!($fd: $t);
140 )*
141 };
142}
143
144impl_argument_getter_setter! {
145 boolean: mbool,
146 integer: mint,
147 real: mreal,
148 cmplex: mcomplex,
149 tensor: MTensor,
150 sparse: MSparseArray,
151 numeric: MNumericArray,
152 image: MImage,
153}
154
155impl InputAdaptor for bool {
156 type Input = mbool;
157
158 #[inline]
159 fn mtype_try_from(input: Self::Input) -> Result<Self> {
160 Ok(input != sys::False)
161 }
162}
163
164impl OutputAdaptor for bool {
165 type Output = mbool;
166
167 #[inline]
168 fn try_into_mtype(self) -> Result<Self::Output> {
169 Ok(if self { sys::True } else { sys::False })
170 }
171}
172
173macro_rules! impl_int_adaptor {
174 ($($t:ty),+) => {
175 $(
176 impl InputAdaptor for $t {
177 type Input = mint;
178
179 #[inline]
180 fn mtype_try_from(input: Self::Input) -> Result<Self> {
181 input
182 .try_into()
183 .map_err(|_| Error::from(ErrorKind::TypeError))
184 }
185 }
186 impl OutputAdaptor for $t {
187 type Output = mint;
188
189 #[inline]
190 fn try_into_mtype(self) -> Result<Self::Output> {
191 self.try_into()
192 .map_err(|_| Error::from(ErrorKind::TypeError))
193 }
194 }
195 )+
196 }
197}
198
199impl_int_adaptor!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
200
201macro_rules! impl_wrapping_int_adaptor {
202 ($($t:ty),+) => {
203 $(
204 impl InputAdaptor for Wrapping<$t> {
205 type Input = mint;
206
207 #[inline]
208 fn mtype_try_from(input: Self::Input) -> Result<Self> {
209 Ok(Wrapping(<$t>::mtype_try_from(input)?))
210 }
211 }
212 impl OutputAdaptor for Wrapping<$t> {
213 type Output = mint;
214
215 #[inline]
216 fn try_into_mtype(self) -> Result<Self::Output> {
217 self.0.try_into_mtype()
218 }
219 }
220 )+
221 };
222}
223
224impl_wrapping_int_adaptor!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
225
226macro_rules! impl_real_adaptor {
227 ($($t:ty),+) => {
228 $(
229 impl InputAdaptor for $t {
230 type Input = mreal;
231
232 fn mtype_try_from(input: Self::Input) -> Result<Self> {
233 Ok(input as Self)
234 }
235 }
236 impl OutputAdaptor for $t {
237 type Output = mreal;
238
239 fn try_into_mtype(self) -> Result<Self::Output> {
240 Ok(self as Self::Output)
241 }
242 }
243 )+
244 };
245}
246
247impl_real_adaptor!(f32, f64);
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252 use std::mem::MaybeUninit;
253 use sys::{mbool, MArgument};
254
255 #[test]
256 fn bool_true_input() {
257 assert_eq!(bool::mtype_try_from(sys::True), Ok(true));
258 }
259
260 #[test]
261 fn bool_false_input() {
262 assert_eq!(bool::mtype_try_from(sys::False), Ok(false));
263 }
264
265 #[test]
266 fn bool_true_output() {
267 assert_eq!(true.try_into_mtype(), Ok(sys::True));
268 }
269
270 #[test]
271 fn bool_false_output() {
272 assert_eq!(false.try_into_mtype(), Ok(sys::False));
273 }
274
275 #[test]
276 fn bool_true_get() {
277 let mut mb = sys::True;
278 let arg = MArgument { boolean: &mut mb };
279 assert_eq!(bool::try_get_arg(arg), Ok(true));
280 }
281
282 #[test]
283 fn bool_false_get() {
284 let mut mb = sys::False;
285 let arg = MArgument { boolean: &mut mb };
286 assert_eq!(bool::try_get_arg(arg), Ok(false));
287 }
288
289 #[test]
290 fn bool_true_set() {
291 let mut mb = MaybeUninit::<mbool>::uninit();
292 let arg = MArgument {
293 boolean: mb.as_mut_ptr(),
294 };
295 let res = true.try_set_arg(&arg);
296 let mb = unsafe { mb.assume_init() };
297 assert_eq!((mb, res), (sys::True, Ok(())));
298 }
299
300 #[test]
301 fn bool_false_set() {
302 let mut mb = MaybeUninit::<mbool>::uninit();
303 let arg = MArgument {
304 boolean: mb.as_mut_ptr(),
305 };
306 let res = false.try_set_arg(&arg);
307 let mb = unsafe { mb.assume_init() };
308 assert_eq!((mb, res), (sys::False, Ok(())));
309 }
310}