1use std::{
5 cell::RefCell,
6 ffi::{CStr, CString},
7 os::raw::c_char,
8};
9
10use ref_cast::RefCast;
11
12use crate::{
13 expr::{Expr, Symbol},
14 rtl,
15 sys::{self, mint, mreal, MArgument},
16 wstp::Link,
17 DataStore, Image, NumericArray,
18};
19
20pub trait FromArg<'a> {
22 #[allow(missing_docs)]
23 unsafe fn from_arg(arg: &'a MArgument) -> Self;
24
25 fn parameter_type() -> Expr;
40}
41
42pub trait IntoArg {
48 unsafe fn into_arg(self, arg: MArgument);
64
65 fn return_type() -> Expr;
69}
70
71pub trait NativeFunction<'a> {
82 unsafe fn call(&self, args: &'a [MArgument], ret: MArgument);
84
85 fn signature(&self) -> Result<(Vec<Expr>, Expr), String>;
96}
97
98pub trait WstpFunction {
110 unsafe fn call(&self, link: &mut Link);
112}
113
114impl FromArg<'_> for bool {
119 unsafe fn from_arg(arg: &MArgument) -> Self {
120 crate::bool_from_mbool(*arg.boolean)
121 }
122
123 fn parameter_type() -> Expr {
124 Expr::string("Boolean")
125 }
126}
127
128impl FromArg<'_> for mint {
129 unsafe fn from_arg(arg: &MArgument) -> Self {
130 *arg.integer
131 }
132
133 fn parameter_type() -> Expr {
134 Expr::symbol(Symbol::new("System`Integer"))
135 }
136}
137
138impl FromArg<'_> for mreal {
139 unsafe fn from_arg(arg: &MArgument) -> Self {
140 *arg.real
141 }
142
143 fn parameter_type() -> Expr {
144 Expr::symbol(Symbol::new("System`Real"))
145 }
146}
147
148impl FromArg<'_> for sys::mcomplex {
149 unsafe fn from_arg(arg: &MArgument) -> Self {
150 *arg.cmplex
151 }
152
153 fn parameter_type() -> Expr {
154 Expr::symbol(Symbol::new("System`Complex"))
155 }
156}
157
158unsafe fn c_str_from_arg<'a>(arg: &'a MArgument) -> &'a CStr {
163 let cstr: *mut c_char = *arg.utf8string;
164 CStr::from_ptr(cstr)
165}
166
167impl<'a> FromArg<'a> for CString {
168 unsafe fn from_arg(arg: &'a MArgument) -> CString {
169 let owned = {
170 let cstr: &'a CStr = c_str_from_arg(arg);
171 CString::from(cstr)
172 };
173
174 rtl::UTF8String_disown(*arg.utf8string);
176
177 owned
178 }
179
180 fn parameter_type() -> Expr {
181 Expr::symbol(Symbol::new("System`String"))
182 }
183}
184
185impl<'a> FromArg<'a> for String {
189 unsafe fn from_arg(arg: &'a MArgument) -> String {
190 let owned = {
191 let cstr: &'a CStr = c_str_from_arg(arg);
192 let str: &'a str = cstr
193 .to_str()
194 .expect("FromArg for &str: string was not valid UTF-8");
195 str.to_owned()
196 };
197
198 rtl::UTF8String_disown(*arg.utf8string);
200
201 owned
202 }
203
204 fn parameter_type() -> Expr {
205 Expr::symbol(Symbol::new("System`String"))
206 }
207}
208
209impl<'a> FromArg<'a> for &'a CStr {
221 unsafe fn from_arg(arg: &'a MArgument) -> &'a CStr {
222 c_str_from_arg(arg)
223 }
224
225 fn parameter_type() -> Expr {
226 panic!("&CStr cannot be used as a LibraryLink function parameter type")
229 }
230}
231
232impl<'a> FromArg<'a> for &'a str {
245 unsafe fn from_arg(arg: &'a MArgument) -> &'a str {
246 let cstr: &'a CStr = FromArg::<'a>::from_arg(arg);
247 cstr.to_str()
248 .expect("FromArg for &str: string was not valid UTF-8")
249 }
250
251 fn parameter_type() -> Expr {
252 panic!("&str cannot be used as a LibraryLink function parameter type")
254 }
255}
256
257impl<'a, T: crate::NumericArrayType> FromArg<'a> for &'a NumericArray<T> {
284 unsafe fn from_arg(arg: &'a MArgument) -> &'a NumericArray<T> {
285 NumericArray::ref_cast(&*arg.numeric)
286 }
287
288 fn parameter_type() -> Expr {
289 Expr::normal(Symbol::new("System`List"), vec![
302 Expr::normal(Symbol::new("System`LibraryDataType"), vec![
303 Expr::from(Symbol::new("System`NumericArray")),
304 Expr::string(T::TYPE.name()),
305 ]),
306 Expr::string("Constant"),
307 ])
308 }
309}
310
311impl<'a, T: crate::NumericArrayType> FromArg<'a> for NumericArray<T> {
312 unsafe fn from_arg(arg: &'a MArgument) -> NumericArray<T> {
313 NumericArray::from_raw(*arg.numeric)
314 }
315
316 fn parameter_type() -> Expr {
317 Expr::normal(Symbol::new("System`List"), vec![
319 Expr::normal(Symbol::new("System`LibraryDataType"), vec![
320 Expr::from(Symbol::new("System`NumericArray")),
321 Expr::string(T::TYPE.name()),
322 ]),
323 Expr::string("Shared"),
324 ])
325 }
326}
327
328impl<'a> FromArg<'a> for &'a NumericArray<()> {
329 unsafe fn from_arg(arg: &'a MArgument) -> &'a NumericArray<()> {
330 NumericArray::ref_cast(&*arg.numeric)
331 }
332
333 fn parameter_type() -> Expr {
334 Expr::normal(Symbol::new("System`List"), vec![
336 Expr::from(Symbol::new("System`NumericArray")),
337 Expr::string("Constant"),
338 ])
339 }
340}
341
342impl<'a> FromArg<'a> for NumericArray<()> {
343 unsafe fn from_arg(arg: &'a MArgument) -> NumericArray<()> {
344 NumericArray::from_raw(*arg.numeric)
345 }
346
347 fn parameter_type() -> Expr {
348 Expr::normal(Symbol::new("System`List"), vec![
350 Expr::from(Symbol::new("System`NumericArray")),
351 Expr::string("Shared"),
352 ])
353 }
354}
355
356impl<'a, T: crate::ImageData> FromArg<'a> for &'a Image<T> {
361 unsafe fn from_arg(arg: &'a MArgument) -> &'a Image<T> {
362 Image::ref_cast(&*arg.image)
363 }
364
365 fn parameter_type() -> Expr {
366 Expr::normal(Symbol::new("System`List"), vec![
368 Expr::normal(Symbol::new("System`LibraryDataType"), vec![
369 Expr::normal(Symbol::new("System`Alternatives"), vec![
370 Expr::from(Symbol::new("System`Image")),
371 Expr::from(Symbol::new("System`Image3D")),
372 ]),
373 Expr::string(T::TYPE.name()),
374 ]),
375 Expr::string("Constant"),
376 ])
377 }
378}
379
380impl<'a, T: crate::ImageData> FromArg<'a> for Image<T> {
381 unsafe fn from_arg(arg: &'a MArgument) -> Image<T> {
382 Image::from_raw(*arg.image)
383 }
384
385 fn parameter_type() -> Expr {
386 Expr::normal(Symbol::new("System`List"), vec![
388 Expr::normal(Symbol::new("System`LibraryDataType"), vec![
389 Expr::normal(Symbol::new("System`Alternatives"), vec![
390 Expr::from(Symbol::new("System`Image")),
391 Expr::from(Symbol::new("System`Image3D")),
392 ]),
393 Expr::string(T::TYPE.name()),
394 ]),
395 Expr::string("Shared"),
396 ])
397 }
398}
399
400impl<'a> FromArg<'a> for &'a Image<()> {
401 unsafe fn from_arg(arg: &'a MArgument) -> &'a Image<()> {
402 Image::ref_cast(&*arg.image)
403 }
404
405 fn parameter_type() -> Expr {
406 Expr::normal(Symbol::new("System`List"), vec![
408 Expr::normal(Symbol::new("System`Alternatives"), vec![
409 Expr::from(Symbol::new("System`Image")),
410 Expr::from(Symbol::new("System`Image3D")),
411 ]),
412 Expr::string("Constant"),
413 ])
414 }
415}
416
417impl<'a> FromArg<'a> for Image<()> {
418 unsafe fn from_arg(arg: &'a MArgument) -> Image<()> {
419 Image::from_raw(*arg.image)
420 }
421
422 fn parameter_type() -> Expr {
423 Expr::normal(Symbol::new("System`List"), vec![
425 Expr::normal(Symbol::new("System`Alternatives"), vec![
426 Expr::from(Symbol::new("System`Image")),
427 Expr::from(Symbol::new("System`Image3D")),
428 ]),
429 Expr::string("Shared"),
430 ])
431 }
432}
433
434impl FromArg<'_> for DataStore {
439 unsafe fn from_arg(arg: &MArgument) -> DataStore {
440 DataStore::from_raw(*arg.tensor as sys::DataStore)
441 }
442
443 fn parameter_type() -> Expr {
444 Expr::string("DataStore")
445 }
446}
447
448impl<'a> FromArg<'a> for &'a DataStore {
449 unsafe fn from_arg(arg: &MArgument) -> &'a DataStore {
450 DataStore::ref_cast(&*(arg.tensor as *mut sys::DataStore))
451 }
452
453 fn parameter_type() -> Expr {
454 panic!("&DataStore cannot be used as a LibraryLink function parameter type")
456 }
457}
458
459impl IntoArg for () {
464 unsafe fn into_arg(self, _arg: MArgument) {
465 }
467
468 fn return_type() -> Expr {
469 Expr::string("Void")
470 }
471}
472
473impl IntoArg for bool {
478 unsafe fn into_arg(self, arg: MArgument) {
479 let boole: u32 = if self { sys::True } else { sys::False };
480 *arg.boolean = boole as sys::mbool;
481 }
482
483 fn return_type() -> Expr {
484 Expr::string("Boolean")
485 }
486}
487
488impl IntoArg for mint {
489 unsafe fn into_arg(self, arg: MArgument) {
490 *arg.integer = self;
491 }
492
493 fn return_type() -> Expr {
494 Expr::symbol(Symbol::new("System`Integer"))
495 }
496}
497
498impl IntoArg for mreal {
499 unsafe fn into_arg(self, arg: MArgument) {
500 *arg.real = self;
501 }
502
503 fn return_type() -> Expr {
504 Expr::symbol(Symbol::new("System`Real"))
505 }
506}
507
508impl IntoArg for sys::mcomplex {
509 unsafe fn into_arg(self, arg: MArgument) {
510 *arg.cmplex = self;
511 }
512
513 fn return_type() -> Expr {
514 Expr::symbol(Symbol::new("System`Complex"))
515 }
516}
517
518impl IntoArg for i8 {
523 unsafe fn into_arg(self, arg: MArgument) {
524 *arg.integer = mint::from(self);
525 }
526
527 fn return_type() -> Expr {
528 Expr::symbol(Symbol::new("System`Integer"))
529 }
530}
531
532impl IntoArg for i16 {
533 unsafe fn into_arg(self, arg: MArgument) {
534 *arg.integer = mint::from(self);
535 }
536
537 fn return_type() -> Expr {
538 Expr::symbol(Symbol::new("System`Integer"))
539 }
540}
541
542impl IntoArg for i32 {
543 unsafe fn into_arg(self, arg: MArgument) {
544 *arg.integer = mint::from(self);
545 }
546
547 fn return_type() -> Expr {
548 Expr::symbol(Symbol::new("System`Integer"))
549 }
550}
551
552impl IntoArg for u8 {
553 unsafe fn into_arg(self, arg: MArgument) {
554 *arg.integer = mint::from(self);
555 }
556
557 fn return_type() -> Expr {
558 Expr::symbol(Symbol::new("System`Integer"))
559 }
560}
561
562impl IntoArg for u16 {
563 unsafe fn into_arg(self, arg: MArgument) {
564 *arg.integer = mint::from(self);
565 }
566
567 fn return_type() -> Expr {
568 Expr::symbol(Symbol::new("System`Integer"))
569 }
570}
571
572#[cfg(target_pointer_width = "64")]
575impl IntoArg for u32 {
576 unsafe fn into_arg(self, arg: MArgument) {
577 *arg.integer = mint::from(self);
578 }
579
580 fn return_type() -> Expr {
581 Expr::symbol(Symbol::new("System`Integer"))
582 }
583}
584
585thread_local! {
590 static RETURNED_STRING: RefCell<Option<CString>> = RefCell::new(None);
593}
594
595impl IntoArg for CString {
596 unsafe fn into_arg(self, arg: MArgument) {
597 let raw: *const c_char = RETURNED_STRING.with(|stored| {
610 if let Some(prev) = stored.replace(None) {
612 drop(prev);
613 }
614
615 let raw: *const c_char = self.as_ptr();
616
617 *stored.borrow_mut() = Some(self);
618
619 raw
620 });
621
622 *arg.utf8string = raw as *mut c_char;
624 }
625
626 fn return_type() -> Expr {
627 Expr::from(Symbol::new("System`String"))
628 }
629}
630
631impl IntoArg for String {
632 unsafe fn into_arg(self, arg: MArgument) {
636 let cstring = CString::new(self)
637 .expect("IntoArg for String: could not convert String to CString");
638
639 <CString as IntoArg>::into_arg(cstring, arg)
640 }
641
642 fn return_type() -> Expr {
643 Expr::from(Symbol::new("System`String"))
644 }
645}
646
647impl<T: crate::NumericArrayType> IntoArg for NumericArray<T> {
652 unsafe fn into_arg(self, arg: MArgument) {
653 *arg.numeric = self.into_raw();
654 }
655
656 fn return_type() -> Expr {
657 Expr::normal(Symbol::new("System`LibraryDataType"), vec![
659 Expr::from(Symbol::new("System`NumericArray")),
660 Expr::string(T::TYPE.name()),
661 ])
662 }
663}
664
665impl IntoArg for NumericArray<()> {
666 unsafe fn into_arg(self, arg: MArgument) {
667 *arg.numeric = self.into_raw();
668 }
669
670 fn return_type() -> Expr {
671 Expr::from(Symbol::new("System`NumericArray"))
673 }
674}
675
676impl<T: crate::ImageData> IntoArg for Image<T> {
677 unsafe fn into_arg(self, arg: MArgument) {
678 *arg.image = self.into_raw();
679 }
680
681 fn return_type() -> Expr {
682 Expr::normal(Symbol::new("System`List"), vec![
684 Expr::normal(Symbol::new("System`LibraryDataType"), vec![
685 Expr::normal(Symbol::new("System`Alternatives"), vec![
686 Expr::from(Symbol::new("System`Image")),
687 Expr::from(Symbol::new("System`Image3D")),
688 ]),
689 Expr::string(T::TYPE.name()),
690 ]),
691 Expr::string("Shared"),
692 ])
693 }
694}
695
696impl IntoArg for DataStore {
697 unsafe fn into_arg(self, arg: MArgument) {
698 *arg.tensor = self.into_raw() as *mut _;
699 }
700
701 fn return_type() -> Expr {
702 Expr::string("DataStore")
703 }
704}
705
706impl<'a: 'b, 'b> NativeFunction<'a> for fn(&'b [MArgument], MArgument) {
735 unsafe fn call(&self, args: &'a [MArgument], ret: MArgument) {
736 self(args, ret)
737 }
738
739 fn signature(&self) -> Result<(Vec<Expr>, Expr), String> {
740 Err(
741 "fn(&[MArgument], MArgument) function cannot be loaded automatically: \
742 parameter and return types are unknown."
743 .to_owned(),
744 )
745 }
746}
747
748macro_rules! impl_NativeFunction {
753 ($($type:ident),*) => {
754 impl<'a, $($type,)* R> NativeFunction<'a> for fn($($type),*) -> R
755 where
756 R: IntoArg,
757 $($type: FromArg<'a>),*
758 {
759 unsafe fn call(&self, args: &'a [MArgument], ret: MArgument) {
760 #[allow(non_snake_case)]
764 let [$($type,)*] = match args {
765 [$($type,)*] => [$($type,)*],
766 _ => panic!(
767 "LibraryLink function number of arguments ({}) does not match \
768 number of parameters",
769 args.len()
770 ),
771 };
772
773 $(
774 #[allow(non_snake_case)]
775 let $type: $type = $type::from_arg($type);
776 )*
777
778 let result: R = self($($type,)*);
779
780 result.into_arg(ret);
781 }
782
783 fn signature(&self) -> Result<(Vec<Expr>, Expr), String> {
784 let mut param_tys = Vec::new();
785
786 $(
787 param_tys.push($type::parameter_type());
788 )*
789
790 Ok((param_tys, R::return_type()))
791 }
792 }
793 }
794}
795
796impl<'a, R> NativeFunction<'a> for fn() -> R
798where
799 R: IntoArg,
800{
801 unsafe fn call(&self, args: &[MArgument], ret: MArgument) {
802 if args.len() != 0 {
803 panic!(
804 "LibraryLink function number of arguments ({}) does not match number of \
805 parameters",
806 args.len()
807 );
808 }
809
810 let result = self();
811
812 result.into_arg(ret);
813 }
814
815 fn signature(&self) -> Result<(Vec<Expr>, Expr), String> {
816 Ok((Vec::new(), R::return_type()))
817 }
818}
819
820impl_NativeFunction!(A1);
821impl_NativeFunction!(A1, A2);
822impl_NativeFunction!(A1, A2, A3);
823impl_NativeFunction!(A1, A2, A3, A4);
824impl_NativeFunction!(A1, A2, A3, A4, A5);
825impl_NativeFunction!(A1, A2, A3, A4, A5, A6);
826impl_NativeFunction!(A1, A2, A3, A4, A5, A6, A7);
827impl_NativeFunction!(A1, A2, A3, A4, A5, A6, A7, A8);
828impl_NativeFunction!(A1, A2, A3, A4, A5, A6, A7, A8, A9);
829impl_NativeFunction!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
830impl_NativeFunction!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
831impl_NativeFunction!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
832
833impl WstpFunction for fn(&mut Link) {
866 unsafe fn call(&self, link: &mut Link) {
867 self(link)
868 }
869}
870
871impl WstpFunction for fn(Vec<Expr>) -> Expr {
904 unsafe fn call(&self, link: &mut Link) {
905 let args: Vec<Expr> = match get_args_list(link) {
906 Ok(args) => args,
907 Err(message) => panic!("WstpFunction: {}", message),
908 };
909
910 let result: Expr = self(args);
911
912 match link.put_expr(&result) {
913 Ok(()) => (),
914 Err(err) => panic!(
915 "WstpFunction: WSTP error writing return expression to link: {}",
916 err
917 ),
918 }
919 }
920}
921
922impl WstpFunction for fn(Vec<Expr>) {
923 unsafe fn call(&self, link: &mut Link) {
924 let args: Vec<Expr> = match get_args_list(link) {
925 Ok(args) => args,
926 Err(message) => panic!("WstpFunction: {}", message),
927 };
928
929 let _null: () = self(args);
930
931 match link.put_symbol("System`Null") {
932 Ok(()) => (),
933 Err(err) => panic!(
934 "WstpFunction: WSTP error writing return Null expression to link: {}",
935 err
936 ),
937 }
938 }
939}
940
941fn get_args_list(link: &mut Link) -> Result<Vec<Expr>, String> {
946 get_args_list_impl(link).map_err(|err: wstp::Error| {
947 format!("WSTP error reading argument List expression: {}", err)
948 })
949}
950
951fn get_args_list_impl(link: &mut Link) -> Result<Vec<Expr>, wstp::Error> {
952 let arg_count: usize = match link.test_head("List") {
953 Ok(count) => Ok(count),
954 Err(err) if err.code() == Some(wstp::sys::WSEGSEQ) => {
955 link.clear_error();
956 link.test_head("System`List")
957 },
958 Err(err) => Err(err),
959 }?;
960
961 let mut elements: Vec<Expr> = Vec::new();
962
963 for _ in 0..arg_count {
964 let elem = link.get_expr()?;
965 elements.push(elem);
966 }
967
968 Ok(elements)
969}