├── .gitignore ├── examples ├── README.md ├── basic │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── examples.nb ├── tests ├── ui │ ├── empty-setup.rs │ ├── missing-return.stderr │ ├── missing-return.rs │ ├── missing-result.rs │ ├── setup-return.rs │ ├── do-nothing.rs │ ├── complex-conj.rs │ ├── no-input.rs │ ├── complex-int-input.rs │ ├── factorial.rs │ ├── void-return.rs │ ├── complex-int-output.rs │ ├── add-two.rs │ ├── complex-int-input.stderr │ ├── conflict-name.rs │ ├── conflict-name.stderr │ └── redefine-prelude.rs └── run-tests.rs ├── .gitmodules ├── .gitattributes ├── sys ├── include │ ├── wrapper.h │ ├── extern.h │ ├── dllexport.h │ ├── WolframSparseLibrary.h │ ├── WolframRawArrayLibrary.h │ ├── WolframNumericArrayLibrary.h │ ├── WolframImageLibrary.h │ └── WolframLibrary.h ├── wlocate │ └── CMakeLists.txt ├── Cargo.toml ├── src │ └── lib.rs └── build.rs ├── macros ├── Cargo.toml └── src │ └── lib.rs ├── .github └── workflows │ ├── intall-llvm.ps1 │ └── ci.yml ├── README.md ├── Cargo.toml ├── LICENSE └── src ├── global.rs ├── lib.rs ├── errors.rs ├── adaptor.rs └── complex.rs /.gitignore: -------------------------------------------------------------------------------- 1 | **/target 2 | Cargo.lock 3 | .idea 4 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | [![View notebooks](https://wolfr.am/HAAhzkRq)](https://wolfr.am/P4jzPCSH) 4 | -------------------------------------------------------------------------------- /tests/ui/empty-setup.rs: -------------------------------------------------------------------------------- 1 | #[wll::setup] 2 | fn setup() {} 3 | 4 | #[wll::teardown] 5 | fn teardown() {} 6 | 7 | fn main() {} 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "FindMathematica"] 2 | path = sys/FindMathematica 3 | url = https://github.com/sakra/FindMathematica.git 4 | -------------------------------------------------------------------------------- /tests/ui/missing-return.stderr: -------------------------------------------------------------------------------- 1 | error: invalid function signature! 2 | --> $DIR/missing-return.rs:8:1 3 | | 4 | 8 | fn nothing() {} 5 | | ^^^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/ui/missing-return.rs: -------------------------------------------------------------------------------- 1 | #[wll::setup] 2 | fn setup() {} 3 | 4 | #[wll::teardown] 5 | fn teardown() {} 6 | 7 | #[wll::export(do_nothing)] 8 | fn nothing() {} 9 | 10 | fn main() {} 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sh eol=lf 2 | bootstrap eol=lf 3 | configure eol=lf 4 | *.[1-9] eol=lf 5 | 6 | *.bat eol=crlf 7 | *.cmd eol=crlf 8 | *.vbs eol=crlf 9 | -------------------------------------------------------------------------------- /tests/ui/missing-result.rs: -------------------------------------------------------------------------------- 1 | #[wll::setup] 2 | fn setup() {} 3 | 4 | #[wll::teardown] 5 | fn teardown() {} 6 | 7 | #[wll::export] 8 | fn add_two(a: isize, b: isize) -> isize { 9 | a + b 10 | } 11 | 12 | fn main() {} 13 | -------------------------------------------------------------------------------- /sys/include/wrapper.h: -------------------------------------------------------------------------------- 1 | #include "extern.h" 2 | #include "dllexport.h" 3 | #include "WolframLibrary.h" 4 | #include "WolframRawArrayLibrary.h" 5 | #include "WolframNumericArrayLibrary.h" 6 | #include "WolframSparseLibrary.h" 7 | #include "WolframImageLibrary.h" 8 | -------------------------------------------------------------------------------- /tests/ui/setup-return.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::unit_arg)] 2 | use wll::{ErrorKind, Result}; 3 | 4 | #[wll::setup] 5 | fn setup() -> Result<()> { 6 | Err(ErrorKind::FunctionError.into()) 7 | } 8 | 9 | #[wll::teardown] 10 | fn teardown() {} 11 | 12 | fn main() {} 13 | -------------------------------------------------------------------------------- /tests/ui/do-nothing.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::unit_arg)] 2 | use wll::Result; 3 | 4 | #[wll::setup] 5 | fn setup() {} 6 | 7 | #[wll::teardown] 8 | fn teardown() {} 9 | 10 | #[wll::export(do_nothing)] 11 | fn nothing() -> Result<()> { 12 | Ok(()) 13 | } 14 | 15 | fn main() {} 16 | -------------------------------------------------------------------------------- /tests/ui/complex-conj.rs: -------------------------------------------------------------------------------- 1 | use wll::{Complex, Result}; 2 | 3 | #[wll::setup] 4 | fn setup() {} 5 | 6 | #[wll::teardown] 7 | fn teardown() {} 8 | 9 | #[wll::export(conj)] 10 | fn cconj(z: Complex) -> Result> { 11 | Ok(z.conj()) 12 | } 13 | 14 | fn main() {} 15 | -------------------------------------------------------------------------------- /tests/ui/no-input.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use wll::Result; 3 | 4 | #[wll::setup] 5 | fn setup() {} 6 | 7 | #[wll::teardown] 8 | fn teardown() {} 9 | 10 | #[wll::export(size_bytes)] 11 | fn size() -> Result { 12 | Ok(mem::size_of::()) 13 | } 14 | 15 | fn main() {} 16 | -------------------------------------------------------------------------------- /tests/ui/complex-int-input.rs: -------------------------------------------------------------------------------- 1 | use wll::{Complex, Result}; 2 | 3 | #[wll::setup] 4 | fn setup() {} 5 | 6 | #[wll::teardown] 7 | fn teardown() {} 8 | 9 | #[wll::export(conj)] 10 | fn cconj(z: Complex) -> Result> { 11 | Ok(z.conj()) 12 | } 13 | 14 | fn main() {} 15 | -------------------------------------------------------------------------------- /tests/ui/factorial.rs: -------------------------------------------------------------------------------- 1 | use wll::Result; 2 | 3 | #[wll::setup] 4 | fn setup() {} 5 | 6 | #[wll::teardown] 7 | fn teardown() {} 8 | 9 | #[wll::export(factorial)] 10 | fn fac(n: usize) -> Result { 11 | Ok(if n == 0 { 1 } else { n * fac(n - 1)? }) 12 | } 13 | 14 | fn main() {} 15 | -------------------------------------------------------------------------------- /tests/ui/void-return.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::unit_arg)] 2 | use wll::Result; 3 | 4 | #[wll::setup] 5 | fn setup() {} 6 | 7 | #[wll::teardown] 8 | fn teardown() {} 9 | 10 | #[wll::export] 11 | fn print(n: usize) -> Result<()> { 12 | eprintln!("Input: {}", n); 13 | Ok(()) 14 | } 15 | 16 | fn main() {} 17 | -------------------------------------------------------------------------------- /tests/ui/complex-int-output.rs: -------------------------------------------------------------------------------- 1 | use wll::{Complex, Result}; 2 | 3 | #[wll::setup] 4 | fn setup() {} 5 | 6 | #[wll::teardown] 7 | fn teardown() {} 8 | 9 | #[wll::export(round)] 10 | fn cround(z: Complex) -> Result> { 11 | Ok(Complex::new(z.re.round() as i32, z.im.round() as i32)) 12 | } 13 | 14 | fn main() {} 15 | -------------------------------------------------------------------------------- /tests/ui/add-two.rs: -------------------------------------------------------------------------------- 1 | use wll::{ErrorKind, Result}; 2 | 3 | #[wll::setup] 4 | fn setup() {} 5 | 6 | #[wll::teardown] 7 | fn teardown() {} 8 | 9 | #[wll::export] 10 | fn add_two(a: isize, b: isize) -> Result { 11 | a.checked_add(b) 12 | .ok_or_else(|| ErrorKind::NumericalError.into()) 13 | } 14 | 15 | fn main() {} 16 | -------------------------------------------------------------------------------- /examples/basic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "basic" 3 | version = "0.1.0" 4 | authors = ["miroox "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [lib] 9 | crate-type = [ "cdylib" ] 10 | 11 | [features] 12 | auto-link = ["wll/auto-link"] 13 | 14 | [dependencies] 15 | wll = { path = "../..", features = ["macros"] } 16 | -------------------------------------------------------------------------------- /tests/ui/complex-int-input.stderr: -------------------------------------------------------------------------------- 1 | error[E0599]: no function or associated item named `try_get_arg` found for struct `Complex` in the current scope 2 | --> $DIR/complex-int-input.rs:10:13 3 | | 4 | 10 | fn cconj(z: Complex) -> Result> { 5 | | ^^^^^^^^^^^^ function or associated item not found in `Complex` 6 | -------------------------------------------------------------------------------- /tests/ui/conflict-name.rs: -------------------------------------------------------------------------------- 1 | use wll::{ErrorKind, Result}; 2 | 3 | #[wll::setup] 4 | fn setup() {} 5 | 6 | #[wll::teardown] 7 | fn teardown() {} 8 | 9 | #[wll::export(add_two)] 10 | fn add_two(a: isize, b: isize) -> Result { 11 | a.checked_add(b) 12 | .ok_or_else(|| ErrorKind::NumericalError.into()) 13 | } 14 | 15 | fn main() {} 16 | -------------------------------------------------------------------------------- /sys/wlocate/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project (wlocate) 4 | 5 | set (CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../FindMathematica/CMake/Mathematica") 6 | 7 | find_package(Mathematica COMPONENTS WolframLibrary) 8 | 9 | if (${Mathematica_FOUND}) 10 | message(STATUS "RUNTIME_LIBRARY_DIRS=${Mathematica_RUNTIME_LIBRARY_DIRS}") 11 | endif() 12 | -------------------------------------------------------------------------------- /tests/ui/conflict-name.stderr: -------------------------------------------------------------------------------- 1 | error[E0428]: the name `add_two` is defined multiple times 2 | --> $DIR/conflict-name.rs:10:1 3 | | 4 | 9 | #[wll::export(add_two)] 5 | | ----------------------- previous definition of the value `add_two` here 6 | 10 | fn add_two(a: isize, b: isize) -> Result { 7 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `add_two` redefined here 8 | | 9 | = note: `add_two` must be defined only once in the value namespace of this module 10 | -------------------------------------------------------------------------------- /tests/ui/redefine-prelude.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | #[wll::setup] 4 | fn setup() {} 5 | 6 | #[wll::teardown] 7 | fn teardown() {} 8 | 9 | type Result = (); 10 | type Option = (); 11 | #[allow(non_camel_case_types)] 12 | type mint = (); 13 | type MArgument = (); 14 | type MType = (); 15 | type MArgumentGetter = (); 16 | 17 | #[wll::export(factorial)] 18 | fn fac(n: usize) -> wll::Result { 19 | Ok(if n == 0 { 1 } else { n * fac(n - 1)? }) 20 | } 21 | 22 | fn main() {} 23 | -------------------------------------------------------------------------------- /examples/basic/src/lib.rs: -------------------------------------------------------------------------------- 1 | use wll::{ErrorKind, Result}; 2 | 3 | #[wll::setup] 4 | fn setup() {} 5 | 6 | #[wll::teardown] 7 | fn teardown() {} 8 | 9 | #[wll::export] 10 | fn add_two(a: isize, b: isize) -> Result { 11 | a.checked_add(b) 12 | .ok_or_else(|| ErrorKind::NumericalError.into()) 13 | } 14 | 15 | #[wll::export(wfactorial)] 16 | fn wfac(n: usize) -> Result { 17 | Ok(if n == 0 { 18 | 1 19 | } else { 20 | wfac(n - 1)?.wrapping_mul(n) 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wll-sys" 3 | version = "0.1.0" 4 | authors = ["miroox "] 5 | edition = "2018" 6 | license = "MIT" 7 | description = "A low-level bindings for Wolfram LibraryLink." 8 | repository = "https://github.com/miRoox/wll-rs/" 9 | categories = ["external-ffi-bindings", "development-tools::ffi"] 10 | keywords = ["wolfram", "mathematica", "librarylink", "ffi", "bindings"] 11 | 12 | [features] 13 | auto-link = [] 14 | 15 | [build-dependencies] 16 | bindgen = "0.54" 17 | -------------------------------------------------------------------------------- /macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wll-macros" 3 | version = "0.1.0" 4 | authors = ["miroox "] 5 | edition = "2018" 6 | license = "MIT" 7 | description = "Procedural macros for Wolfram LibraryLink interface." 8 | repository = "https://github.com/miRoox/wll-rs/" 9 | categories = ["development-tools::ffi"] 10 | keywords = ["wolfram", "mathematica", "librarylink", "ffi", "macro"] 11 | 12 | [lib] 13 | proc-macro=true 14 | 15 | [dependencies] 16 | syn = { version = "1.0", features = ["full", "extra-traits"] } 17 | quote = "1.0" 18 | proc-macro2 = "1.0" 19 | -------------------------------------------------------------------------------- /tests/run-tests.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | #[cfg_attr(not(feature = "macros"), ignore)] 3 | fn tests() { 4 | let t = trybuild::TestCases::new(); 5 | t.pass("tests/ui/empty-setup.rs"); 6 | t.pass("tests/ui/setup-return.rs"); 7 | t.pass("tests/ui/add-two.rs"); 8 | t.pass("tests/ui/factorial.rs"); 9 | t.compile_fail("tests/ui/conflict-name.rs"); 10 | t.pass("tests/ui/complex-conj.rs"); 11 | t.compile_fail("tests/ui/complex-int-input.rs"); 12 | t.pass("tests/ui/complex-int-output.rs"); 13 | t.pass("tests/ui/no-input.rs"); 14 | t.pass("tests/ui/void-return.rs"); 15 | t.pass("tests/ui/do-nothing.rs"); 16 | t.compile_fail("tests/ui/missing-result.rs"); 17 | t.compile_fail("tests/ui/missing-return.rs"); 18 | t.pass("tests/ui/redefine-prelude.rs"); 19 | } 20 | -------------------------------------------------------------------------------- /sys/include/extern.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | 3 | Mathematica source file 4 | 5 | Copyright 1986 through 2015 by Wolfram Research Inc. 6 | 7 | This material contains trade secrets and may be registered with the 8 | U.S. Copyright Office as an unpublished work, pursuant to Title 17, 9 | U.S. Code, Section 408. Unauthorized copying, adaptation, distribution 10 | or display is prohibited. 11 | 12 | $Id$ 13 | 14 | *************************************************************************/ 15 | 16 | #ifndef EXTERN_H 17 | #define EXTERN_H 18 | 19 | #ifndef EXTERN_C 20 | #ifdef __cplusplus 21 | #define EXTERN_C extern "C" 22 | #else 23 | #define EXTERN_C extern 24 | #endif 25 | #endif 26 | 27 | #endif /* EXTERN_H */ 28 | 29 | -------------------------------------------------------------------------------- /.github/workflows/intall-llvm.ps1: -------------------------------------------------------------------------------- 1 | # based on https://www.powershellgallery.com/packages/AppVeyorBYOC/1.0.170/Content/scripts%5CWindows%5Cinstall_llvm.ps1 2 | 3 | $llvmVersion = "10.0.0" 4 | Write-Host "Installing LLVM $llvmVersion ..." -ForegroundColor Cyan 5 | Write-Host "Downloading..." 6 | $exePath = "$env:temp\LLVM-$llvmVersion-win64.exe" 7 | (New-Object Net.WebClient).DownloadFile("https://github.com/llvm/llvm-project/releases/download/llvmorg-$llvmVersion/LLVM-$llvmVersion-win64.exe", $exePath) 8 | Write-Host "Installing..." 9 | cmd /c start /wait $exePath /S 10 | 11 | $llvmPath = "$env:ProgramFiles\LLVM\bin" 12 | $env:Path = (($env:Path -split ';') + $llvmPath) -join ';' 13 | [System.Environment]::SetEnvironmentVariable("LIBCLANG_PATH", $llvmPath, [System.EnvironmentVariableTarget]::Machine) 14 | 15 | cmd /c clang --version 16 | 17 | Write-Host "Installed" -ForegroundColor Green -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wll-rs 2 | 3 | [![crates.io](https://img.shields.io/crates/v/wll.svg)](https://crates.io/crates/wll) 4 | [![doc.rs](https://docs.rs/wll/badge.svg)](https://docs.rs/wll) 5 | [![CI](https://github.com/miRoox/wll-rs/workflows/CI/badge.svg)](https://github.com/miRoox/wll-rs/actions?query=workflow%3ACI) 6 | 7 | Wolfram [LibraryLink](http://reference.wolfram.com/language/LibraryLink/tutorial/Overview.html) interface for Rust 8 | 9 | Inspired by [wll-interface](https://github.com/njpipeorgan/wll-interface). 10 | 11 | Purpose: 12 | 13 | ```rust 14 | // lib.rs 15 | use wll::{ErrorKind, Result}; 16 | 17 | #[wll::setup] 18 | fn setup() {} 19 | 20 | #[wll::teardown] 21 | fn teardown() {} 22 | 23 | // export function named `wll_add_two` 24 | #[wll::export] 25 | fn add_two(a: isize, b: isize)->Result { 26 | a.checked_add(b) 27 | .ok_or_else(|| ErrorKind::NumericalError.into()) 28 | } 29 | 30 | #[wll::export(factorial)] 31 | fn fac(n: usize) -> Result { 32 | Ok(if n == 0 { 1 } else { n * fac(n - 1)? }) 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wll" 3 | version = "0.1.1" 4 | authors = ["miroox "] 5 | edition = "2018" 6 | license = "MIT" 7 | description = "A Wolfram LibraryLink interface." 8 | readme = "README.md" 9 | repository = "https://github.com/miRoox/wll-rs/" 10 | categories = ["api-bindings", "development-tools::ffi"] 11 | keywords = ["wolfram", "mathematica", "librarylink", "ffi", "wrapper"] 12 | exclude = [ "*.nb" ] 13 | 14 | [package.metadata.docs.rs] 15 | features = ["macros"] 16 | rustdoc-args = ["--cfg", "docsrs"] 17 | 18 | [workspace] 19 | members = [ 20 | "sys", 21 | "macros", 22 | "examples/basic" 23 | ] 24 | 25 | [features] 26 | default = [] 27 | macros = ["wll-macros"] 28 | num-complex-type = ["num-complex"] 29 | auto-link = ["wll-sys/auto-link"] 30 | 31 | [dependencies] 32 | wll-sys = { version = "0.1", path = "sys" } 33 | wll-macros = { version = "0.1", path = "macros", optional = true } 34 | num-complex = { version = "0.3", optional = true} 35 | 36 | [dev-dependencies] 37 | trybuild = { version = "1.0", features = ["diff"] } 38 | 39 | [[test]] 40 | name = "tests" 41 | path = "tests/run-tests.rs" 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2021 miRoox . 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /sys/include/dllexport.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | 3 | Mathematica source file 4 | 5 | Copyright 1986 through 2015 by Wolfram Research Inc. 6 | 7 | This material contains trade secrets and may be registered with the 8 | U.S. Copyright Office as an unpublished work, pursuant to Title 17, 9 | U.S. Code, Section 408. Unauthorized copying, adaptation, distribution 10 | or display is prohibited. 11 | 12 | $Id$ 13 | 14 | *************************************************************************/ 15 | 16 | #ifndef DLL_EXPORT_H 17 | #define DLL_EXPORT_H 18 | 19 | /* Define DLL symbol export for LibraryLink etc */ 20 | 21 | #if defined(_WIN32) || defined(_WIN64) 22 | 23 | #define DLLEXPORT __declspec(dllexport) 24 | #define DLLIMPORT __declspec(dllimport) 25 | 26 | #else 27 | 28 | #define DLLEXPORT __attribute__((__visibility__("default"))) 29 | #define DLLIMPORT 30 | 31 | #endif 32 | 33 | /* Definition for the Runtime Library */ 34 | 35 | #if defined(MRTL_DYNAMIC_EXPORT) 36 | 37 | #define RTL_DLL_EXPORT DLLEXPORT 38 | 39 | #elif defined(MATHDLL_EXPORTS) 40 | 41 | #define RTL_DLL_EXPORT DLLIMPORT 42 | 43 | #else 44 | 45 | #define RTL_DLL_EXPORT 46 | 47 | #endif 48 | 49 | #endif /* DLL_EXPORT_H */ 50 | 51 | -------------------------------------------------------------------------------- /src/global.rs: -------------------------------------------------------------------------------- 1 | // Some internal tools to access the global status. 2 | 3 | use crate::{ErrorKind, Result}; 4 | use std::ptr; 5 | use std::ptr::NonNull; 6 | use std::sync::atomic::{AtomicPtr, Ordering}; 7 | 8 | static CURRENT_LIB_DATA: AtomicPtr = AtomicPtr::new(ptr::null_mut()); 9 | 10 | // Initialize global `WolframLibraryData`. 11 | #[inline] 12 | pub fn initialize_lib_data(lib_data: sys::WolframLibraryData) -> Result<()> { 13 | if lib_data.is_null() { 14 | return Err(ErrorKind::FunctionError.into()); 15 | } 16 | CURRENT_LIB_DATA.store(lib_data, Ordering::Relaxed); 17 | Ok(()) 18 | } 19 | 20 | // Work with current `WolframLibraryData`. 21 | #[inline] 22 | pub fn with_lib_data(f: F) -> Result 23 | where 24 | F: FnOnce(NonNull) -> Result, 25 | { 26 | if let Some(data) = NonNull::new(CURRENT_LIB_DATA.load(Ordering::Relaxed)) { 27 | f(data) 28 | } else { 29 | Err(ErrorKind::FunctionError.into()) 30 | } 31 | } 32 | 33 | // RAII wrapper to set current `WolframLibraryData` locally. 34 | pub struct LibDataLocalizer { 35 | old: sys::WolframLibraryData, 36 | } 37 | 38 | impl LibDataLocalizer { 39 | // Set current `WolframLibraryData` locally. 40 | #[inline] 41 | pub fn new(new: sys::WolframLibraryData) -> Self { 42 | LibDataLocalizer { 43 | old: CURRENT_LIB_DATA.swap(new, Ordering::Release), 44 | } 45 | } 46 | } 47 | 48 | impl Drop for LibDataLocalizer { 49 | // Restore current `WolframLibraryData`. 50 | #[inline] 51 | fn drop(&mut self) { 52 | CURRENT_LIB_DATA.swap(self.old, Ordering::Release); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! `wll-sys` is a low-level bindings for Wolfram LibraryLink. 2 | //! Typically doesn’t need to be used directly. 3 | //! 4 | //! It is automatically generated by [bindgen](https://crates.io/crates/bindgen). 5 | //! 6 | //! **see also**: [Wolfram LibraryLink User Guide], [LibraryLink Reference]. 7 | //! 8 | //! [Wolfram LibraryLink User Guide]: http://reference.wolfram.com/language/LibraryLink/tutorial/Overview.html 9 | //! [LibraryLink Reference]: http://reference.wolfram.com/language/LibraryLink/tutorial/Reference.html 10 | 11 | #![allow(non_upper_case_globals)] 12 | #![allow(non_camel_case_types)] 13 | #![allow(non_snake_case)] 14 | #![allow(clippy::all)] 15 | 16 | mod bindings { 17 | include!(concat!(env!("OUT_DIR"), "/bindings.rs")); 18 | } 19 | 20 | pub use bindings::*; 21 | 22 | pub const True: mbool = bindings::True as mbool; 23 | pub const False: mbool = bindings::False as mbool; 24 | pub const WolframLibraryVersion: mint = bindings::WolframLibraryVersion as mint; 25 | pub const LIBRARY_NO_ERROR: errcode_t = bindings::LIBRARY_NO_ERROR as errcode_t; 26 | pub const LIBRARY_TYPE_ERROR: errcode_t = bindings::LIBRARY_TYPE_ERROR as errcode_t; 27 | pub const LIBRARY_RANK_ERROR: errcode_t = bindings::LIBRARY_RANK_ERROR as errcode_t; 28 | pub const LIBRARY_DIMENSION_ERROR: errcode_t = bindings::LIBRARY_DIMENSION_ERROR as errcode_t; 29 | pub const LIBRARY_NUMERICAL_ERROR: errcode_t = bindings::LIBRARY_NUMERICAL_ERROR as errcode_t; 30 | pub const LIBRARY_MEMORY_ERROR: errcode_t = bindings::LIBRARY_MEMORY_ERROR as errcode_t; 31 | pub const LIBRARY_FUNCTION_ERROR: errcode_t = bindings::LIBRARY_FUNCTION_ERROR as errcode_t; 32 | pub const LIBRARY_VERSION_ERROR: errcode_t = bindings::LIBRARY_VERSION_ERROR as errcode_t; 33 | -------------------------------------------------------------------------------- /sys/build.rs: -------------------------------------------------------------------------------- 1 | extern crate bindgen; 2 | 3 | use std::env; 4 | use std::path::PathBuf; 5 | use std::process::Command; 6 | 7 | fn main() { 8 | let include_path = PathBuf::from("include"); 9 | let wrapper_file = include_path.join("wrapper.h"); 10 | if cfg!(feature = "auto-link") { 11 | link_libraries(); 12 | } 13 | println!("cargo:rerun-if-changed={}", include_path.to_str().unwrap()); 14 | let bindings = bindgen::Builder::default() 15 | .header(wrapper_file.to_str().unwrap()) 16 | .parse_callbacks(Box::new(bindgen::CargoCallbacks)) 17 | .generate() 18 | .expect("Unable to generate bindings"); 19 | let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); 20 | bindings 21 | .write_to_file(out_path.join("bindings.rs")) 22 | .expect("Couldn't write bindings!"); 23 | } 24 | 25 | fn link_libraries() { 26 | if !env::var("DOCS_RS").is_ok() { 27 | find_library_paths(); 28 | println!("cargo:rustc-link-lib=dylib={}", wolfram_library_name()); 29 | } 30 | } 31 | 32 | fn find_library_paths() { 33 | let start = "-- RUNTIME_LIBRARY_DIRS="; 34 | let output = Command::new("cmake") 35 | .current_dir("wlocate") 36 | .arg(".") 37 | .output() 38 | .expect("Failed to execute cmake"); 39 | let msg = String::from_utf8(output.stdout).expect("Invalid character in output of cmake"); 40 | msg.lines() 41 | .find(|s| s.starts_with(start)) 42 | .expect("Do not find Wolfram Runtime Library") 43 | .trim_start_matches(start) 44 | .split_terminator(';') 45 | .for_each(|p| println!("cargo:rustc-link-search=native={}", p)); 46 | } 47 | 48 | fn wolfram_library_name() -> &'static str { 49 | "WolframRTL" 50 | } 51 | -------------------------------------------------------------------------------- /sys/include/WolframSparseLibrary.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | Mathematica source file 3 | 4 | Copyright 1986 through 2015 by Wolfram Research Inc. 5 | 6 | This material contains trade secrets and may be registered with the 7 | U.S. Copyright Office as an unpublished work, pursuant to Title 17, 8 | U.S. Code, Section 408. Unauthorized copying, adaptation, distribution 9 | or display is prohibited. 10 | 11 | $Id$ 12 | 13 | *************************************************************************/ 14 | 15 | #ifndef WOLFRAMSPARSELIBRARY_H 16 | #define WOLFRAMSPARSELIBRARY_H 17 | 18 | #include "WolframLibrary.h" 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | typedef struct st_WolframSparseLibrary_Functions 25 | { 26 | int (*MSparseArray_clone)(MSparseArray, MSparseArray *); 27 | void (*MSparseArray_free)(MSparseArray); 28 | void (*MSparseArray_disown)(MSparseArray); 29 | void (*MSparseArray_disownAll)(MSparseArray); 30 | mint (*MSparseArray_shareCount)(MSparseArray); 31 | mint (*MSparseArray_getRank)(MSparseArray); 32 | mint const * (*MSparseArray_getDimensions)(MSparseArray); 33 | MTensor *(*MSparseArray_getImplicitValue)(MSparseArray); 34 | MTensor *(*MSparseArray_getExplicitValues)(MSparseArray); 35 | MTensor *(*MSparseArray_getRowPointers)(MSparseArray); 36 | MTensor *(*MSparseArray_getColumnIndices)(MSparseArray); 37 | int (*MSparseArray_getExplicitPositions)(MSparseArray, MTensor *); 38 | int (*MSparseArray_resetImplicitValue)(MSparseArray, MTensor, MSparseArray *); 39 | int (*MSparseArray_toMTensor)(MSparseArray, MTensor *); 40 | int (*MSparseArray_fromMTensor)(MTensor, MTensor, MSparseArray *); 41 | int (*MSparseArray_fromExplicitPositions)(MTensor, MTensor, MTensor, MTensor, MSparseArray *); 42 | } *WolframSparseLibrary_Functions; 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | rust-test: 7 | name: Run rust tests on ${{ matrix.os }} with ${{ matrix.features }} 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | os: [windows-latest, macos-latest, ubuntu-latest] 13 | features: ['"macros"', '"macros num-complex-type"'] 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Setup rust 17 | uses: dtolnay/rust-toolchain@master 18 | with: 19 | toolchain: nightly 20 | - name: Install LLVM for Windows 21 | if: ${{ startsWith(matrix.os, 'windows') }} 22 | run: .\.github\workflows\intall-llvm.ps1 23 | shell: powershell 24 | - name: Build 25 | run: cargo build --workspace --verbose --features ${{ matrix.features }} 26 | - name: Test 27 | run: cargo test --workspace --verbose --features ${{ matrix.features }} 28 | wolfram-test: 29 | name: Run Wolfram tests 30 | runs-on: ubuntu-latest 31 | steps: 32 | - uses: actions/checkout@v2 33 | with: 34 | submodules: true 35 | - name: Setup rust 36 | uses: dtolnay/rust-toolchain@master 37 | with: 38 | toolchain: nightly 39 | - name: Install Wolfram Engine 40 | run: | 41 | wget https://account.wolfram.com/download/public/wolfram-engine/desktop/LINUX 42 | sudo bash LINUX -- -auto -verbose 43 | rm LINUX 44 | - name: Activate Wolfram Engine 45 | run: | 46 | /usr/bin/wolframscript -authenticate $WOLFRAM_ID $WOLFRAM_PW 47 | /usr/bin/wolframscript -activate 48 | env: 49 | WOLFRAM_ID: ${{ secrets.Wolfram_ID }} 50 | WOLFRAM_PW: ${{ secrets.Wolfram_PW }} 51 | - name: Build with link 52 | run: cargo build --workspace --verbose --features "auto-link macros" 53 | -------------------------------------------------------------------------------- /sys/include/WolframRawArrayLibrary.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | Mathematica source file 3 | 4 | Copyright 1986 through 2000 by Wolfram Research Inc. 5 | 6 | This material contains trade secrets and may be registered with the 7 | U.S. Copyright Office as an unpublished work, pursuant to Title 17, 8 | U.S. Code, Section 408. Unauthorized copying, adaptation, distribution 9 | or display is prohibited. 10 | 11 | $Id: WolframRawArrayLibrary.h,v Exp $ 12 | 13 | *************************************************************************/ 14 | 15 | #ifndef WOLFRAMRAWARRAYLIBRARY_H 16 | #define WOLFRAMRAWARRAYLIBRARY_H 17 | 18 | #include "WolframLibrary.h" 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | enum MRawArray_Data_Type { 25 | MRawArray_Type_Undef = 0, 26 | MRawArray_Type_Bit8 = 1, 27 | MRawArray_Type_Ubit8, 28 | MRawArray_Type_Bit16, 29 | MRawArray_Type_Ubit16, 30 | MRawArray_Type_Bit32, 31 | MRawArray_Type_Ubit32, 32 | MRawArray_Type_Bit64, 33 | MRawArray_Type_Ubit64, 34 | MRawArray_Type_Real32, 35 | MRawArray_Type_Real64, 36 | MRawArray_Type_Float_Complex, 37 | MRawArray_Type_Double_Complex 38 | }; 39 | 40 | typedef enum MRawArray_Data_Type rawarray_t; 41 | 42 | typedef struct st_WolframRawArrayLibrary_Functions 43 | { 44 | int(*MRawArray_new)(rawarray_t, mint, mint const*, MRawArray *); 45 | void (*MRawArray_free)(MRawArray); 46 | int(*MRawArray_clone)(MRawArray, MRawArray *); 47 | void (*MRawArray_disown)(MRawArray); 48 | void (*MRawArray_disownAll)(MRawArray); 49 | mint (*MRawArray_shareCount)(MRawArray); 50 | 51 | rawarray_t (*MRawArray_getType)( MRawArray); 52 | mint (*MRawArray_getRank)(MRawArray); 53 | mint const * (*MRawArray_getDimensions)(MRawArray); 54 | mint (*MRawArray_getFlattenedLength)(MRawArray); 55 | void* (*MRawArray_getData)(MRawArray); 56 | MRawArray (*MRawArray_convertType)(MRawArray, rawarray_t); 57 | } *WolframRawArrayLibrary_Functions; 58 | 59 | #ifdef __cplusplus 60 | } 61 | #endif 62 | 63 | #endif 64 | 65 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Wolfram [LibraryLink] interface for Rust. 2 | //! 3 | //! # Examples 4 | //! 5 | //! Examples can found in the examples directory of the source code, or on [GitHub](https://github.com/miRoox/wll-rs/tree/master/examples). 6 | //! 7 | //! [LibraryLink]: http://reference.wolfram.com/language/LibraryLink/tutorial/Overview.html 8 | 9 | #![feature(doc_cfg)] 10 | 11 | #[cfg(feature = "macros")] 12 | #[no_link] 13 | #[allow(unused_imports)] 14 | #[macro_use] 15 | extern crate wll_macros; 16 | #[cfg(feature = "num-complex-type")] 17 | extern crate num_complex; 18 | #[doc(hidden)] 19 | pub extern crate wll_sys as sys; 20 | 21 | #[cfg(not(feature = "num-complex-type"))] 22 | pub use complex::Complex; 23 | pub use errors::{Error, ErrorKind}; 24 | #[cfg(feature = "num-complex-type")] 25 | pub use num_complex::Complex; 26 | #[cfg(feature = "macros")] 27 | #[cfg_attr(docsrs, doc(cfg(feature = "macros")))] 28 | pub use wll_macros::*; 29 | 30 | pub mod adaptor; 31 | #[doc(hidden)] 32 | pub mod global; 33 | 34 | mod complex; 35 | mod errors; 36 | 37 | /// A specialized `std::result::Result` type for wll functions. 38 | pub type Result = std::result::Result; 39 | 40 | /// Issues a message from a library function. 41 | /// 42 | /// **see also**: [Message](http://reference.wolfram.com/language/LibraryLink/ref/callback/Message.html) 43 | #[inline] 44 | pub fn message(msg: &'static str) -> Result<()> { 45 | global::with_lib_data(|data| unsafe { 46 | let func = (*data.as_ptr()) 47 | .Message 48 | .unwrap_or_else(|| std::hint::unreachable_unchecked()); 49 | func(msg.as_ptr() as *const ::std::os::raw::c_char); 50 | Ok(()) 51 | }) 52 | } 53 | 54 | /// Checks if the Wolfram Language is in the process of an abort. 55 | /// 56 | /// **see also**: [AbortQ](http://reference.wolfram.com/language/LibraryLink/ref/callback/AbortQ.html) 57 | #[inline] 58 | pub fn is_abort() -> Result { 59 | global::with_lib_data(|data| unsafe { 60 | Ok((*data.as_ptr()) 61 | .AbortQ 62 | .unwrap_or_else(|| std::hint::unreachable_unchecked())() 63 | != 0) 64 | }) 65 | } 66 | -------------------------------------------------------------------------------- /sys/include/WolframNumericArrayLibrary.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | Mathematica source file 3 | 4 | Copyright 1986 through 2000 by Wolfram Research Inc. 5 | 6 | This material contains trade secrets and may be registered with the 7 | U.S. Copyright Office as an unpublished work, pursuant to Title 17, 8 | U.S. Code, Section 408. Unauthorized copying, adaptation, distribution 9 | or display is prohibited. 10 | 11 | *************************************************************************/ 12 | 13 | #ifndef WOLFRAMNUMERICARRAYLIBRARY_H 14 | #define WOLFRAMNUMERICARRAYLIBRARY_H 15 | 16 | #include "WolframLibrary.h" 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | enum MNumericArray_Data_Type { 23 | MNumericArray_Type_Undef = 0, 24 | MNumericArray_Type_Bit8 = 1, 25 | MNumericArray_Type_UBit8, 26 | MNumericArray_Type_Bit16, 27 | MNumericArray_Type_UBit16, 28 | MNumericArray_Type_Bit32, 29 | MNumericArray_Type_UBit32, 30 | MNumericArray_Type_Bit64, 31 | MNumericArray_Type_UBit64, 32 | MNumericArray_Type_Real32, 33 | MNumericArray_Type_Real64, 34 | MNumericArray_Type_Complex_Real32, 35 | MNumericArray_Type_Complex_Real64 36 | }; 37 | 38 | typedef enum MNumericArray_Data_Type numericarray_data_t; 39 | 40 | enum MNumericArray_Convert_Method { 41 | MNumericArray_Convert_Check = 1, 42 | MNumericArray_Convert_Clip_Check, 43 | MNumericArray_Convert_Coerce, 44 | MNumericArray_Convert_Clip_Coerce, 45 | MNumericArray_Convert_Round, 46 | MNumericArray_Convert_Clip_Round, 47 | MNumericArray_Convert_Scale, 48 | MNumericArray_Convert_Clip_Scale 49 | }; 50 | 51 | typedef enum MNumericArray_Convert_Method numericarray_convert_method_t; 52 | 53 | typedef struct st_WolframNumericArrayLibrary_Functions 54 | { 55 | errcode_t (*MNumericArray_new)(const numericarray_data_t, const mint, const mint*, MNumericArray*); 56 | void (*MNumericArray_free)(MNumericArray); 57 | errcode_t (*MNumericArray_clone)(const MNumericArray, MNumericArray*); 58 | void (*MNumericArray_disown)(MNumericArray); 59 | void (*MNumericArray_disownAll)(MNumericArray); 60 | mint (*MNumericArray_shareCount)(const MNumericArray); 61 | 62 | numericarray_data_t (*MNumericArray_getType)(const MNumericArray); 63 | mint (*MNumericArray_getRank)(const MNumericArray); 64 | mint const* (*MNumericArray_getDimensions)(const MNumericArray); 65 | mint (*MNumericArray_getFlattenedLength)(const MNumericArray); 66 | void* (*MNumericArray_getData)(const MNumericArray); 67 | errcode_t (*MNumericArray_convertType)(MNumericArray*, const MNumericArray, const numericarray_data_t, const numericarray_convert_method_t, const mreal); 68 | }* WolframNumericArrayLibrary_Functions; 69 | 70 | #ifdef __cplusplus 71 | } 72 | #endif 73 | 74 | #endif 75 | 76 | -------------------------------------------------------------------------------- /sys/include/WolframImageLibrary.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | Mathematica source file 3 | 4 | Copyright 1986 through 2015 by Wolfram Research Inc. 5 | 6 | This material contains trade secrets and may be registered with the 7 | U.S. Copyright Office as an unpublished work, pursuant to Title 17, 8 | U.S. Code, Section 408. Unauthorized copying, adaptation, distribution 9 | or display is prohibited. 10 | 11 | $Id$ 12 | 13 | *************************************************************************/ 14 | 15 | #ifndef WOLFRAMIMAGELIBRARY_H 16 | #define WOLFRAMIMAGELIBRARY_H 17 | 18 | #include "WolframLibrary.h" 19 | 20 | #if !(defined(MATHEMATICA_KERNEL) || defined(MATHEMATICA_RUNTIME)) 21 | 22 | typedef signed char raw_t_bit; 23 | typedef unsigned char raw_t_ubit8; 24 | typedef unsigned short raw_t_ubit16; 25 | typedef float raw_t_real32; 26 | typedef double raw_t_real64; 27 | 28 | #endif 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | enum MImage_Data_Type { 35 | MImage_Type_Undef = -1, 36 | MImage_Type_Bit, 37 | MImage_Type_Bit8, 38 | MImage_Type_Bit16, 39 | MImage_Type_Real32, 40 | MImage_Type_Real 41 | }; 42 | 43 | typedef enum MImage_Data_Type imagedata_t; 44 | 45 | enum MImage_CS_Type { 46 | MImage_CS_Undef = -1, 47 | MImage_CS_Gray, 48 | MImage_CS_RGB, 49 | MImage_CS_HSB, 50 | MImage_CS_CMYK, 51 | MImage_CS_XYZ, 52 | MImage_CS_LUV, 53 | MImage_CS_LAB, 54 | MImage_CS_LCH, 55 | MImage_CS_Automatic 56 | }; 57 | 58 | typedef enum MImage_CS_Type colorspace_t; 59 | 60 | 61 | typedef struct st_WolframImageLibrary_Functions 62 | { 63 | int (*MImage_new2D)(mint /* width */, mint /* height */, mint /* channels */, imagedata_t /* type */, colorspace_t /* colorSpace */, mbool /* interleaving */, MImage * /* result */); 64 | int (*MImage_new3D)(mint /* slices */, mint /* width */, mint /* height */, mint /* channels */, imagedata_t /* type */, colorspace_t /* colorSpace */, mbool /* interleaving */, MImage * /* result */); 65 | int (*MImage_clone)(MImage, MImage *); 66 | void (*MImage_free)(MImage); 67 | void (*MImage_disown)(MImage); 68 | void (*MImage_disownAll)(MImage); 69 | mint (*MImage_shareCount)(MImage); 70 | 71 | imagedata_t (*MImage_getDataType)(MImage); 72 | mint (*MImage_getRowCount)(MImage); 73 | mint (*MImage_getColumnCount)(MImage); 74 | mint (*MImage_getSliceCount)(MImage); 75 | mint (*MImage_getRank)(MImage); 76 | mint (*MImage_getChannels)(MImage); 77 | mbool (*MImage_alphaChannelQ)(MImage); 78 | mbool (*MImage_interleavedQ)(MImage); 79 | colorspace_t (*MImage_getColorSpace)(MImage); 80 | mint (*MImage_getFlattenedLength)(MImage); 81 | 82 | int (*MImage_getBit)(MImage /* image */, mint * /* pos */, mint /* channel */, raw_t_bit * /* result */); 83 | int (*MImage_getByte)(MImage /* image */, mint * /* pos */, mint /* channel */, raw_t_ubit8 * /* result */); 84 | int (*MImage_getBit16)(MImage /* image */, mint * /* pos */, mint /* channel */, raw_t_ubit16 * /* result */); 85 | int (*MImage_getReal32)(MImage /* image */, mint * /* pos */, mint /* channel */, raw_t_real32 * /* result */); 86 | int (*MImage_getReal)(MImage /* image */, mint * /* pos */, mint /* channel */, raw_t_real64 * /* result */); 87 | 88 | int (*MImage_setBit)(MImage /* image */, mint * /* pos */, mint /* channel */, raw_t_bit /* value */); 89 | int (*MImage_setByte)(MImage /* image */, mint * /* pos */, mint /* channel */, raw_t_ubit8 /* value */); 90 | int (*MImage_setBit16)(MImage /* image */, mint * /* pos */, mint /* channel */, raw_t_ubit16 /* value */); 91 | int (*MImage_setReal32)(MImage /* image */, mint * /* pos */, mint /* channel */, raw_t_real32 /* value */); 92 | int (*MImage_setReal)(MImage /* image */, mint * /* pos */, mint /* channel */, raw_t_real64 /* value */); 93 | 94 | void *(*MImage_getRawData)(MImage); 95 | raw_t_bit* (*MImage_getBitData)(MImage); 96 | raw_t_ubit8* (*MImage_getByteData)(MImage); 97 | raw_t_ubit16* (*MImage_getBit16Data)(MImage); 98 | raw_t_real32* (*MImage_getReal32Data)(MImage); 99 | raw_t_real64* (*MImage_getRealData)(MImage); 100 | 101 | MImage (*MImage_convertType)(MImage, imagedata_t /* type */, mbool /* interleaving */); 102 | 103 | 104 | } *WolframImageLibrary_Functions; 105 | 106 | #ifdef __cplusplus 107 | } 108 | #endif 109 | 110 | #endif 111 | 112 | -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | //! Wolfram LibraryLink errors. 2 | 3 | use std::fmt::{self, Display, Formatter}; 4 | use sys::errcode_t; 5 | 6 | /// The error type for Wolfram LibraryLink. 7 | /// 8 | /// **see also**: [Library Structure and Life Cycle: Errors](https://reference.wolfram.com/language/LibraryLink/tutorial/LibraryStructure.html#59563264). 9 | #[derive(Debug, Eq, PartialEq, Clone)] 10 | pub struct Error(Repr); 11 | 12 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] 13 | enum Repr { 14 | Simple(ErrorKind), 15 | Raw(errcode_t), 16 | } 17 | 18 | /// A list specifying general categories of Wolfram LibraryLink error. 19 | /// 20 | /// It is used with the [`Error`] type. 21 | /// 22 | /// [`Error`]: ./struct.Error.html 23 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] 24 | pub enum ErrorKind { 25 | /// Unexpected type encountered. 26 | TypeError = 1, 27 | /// Unexpected rank encountered. 28 | RankError, 29 | /// Inconsistent dimensions encountered. 30 | DimensionError, 31 | /// Error in numerical computation. 32 | NumericalError, 33 | /// Problem allocating memory. 34 | MemoryError, 35 | /// Generic error from a function. 36 | FunctionError, 37 | /// Incompatible version. 38 | VersionError, 39 | } 40 | 41 | impl Error { 42 | /// Creates a new instance of an `Error` from a raw error code. 43 | #[inline] 44 | pub fn from_raw_error(code: errcode_t) -> Option { 45 | if code == sys::LIBRARY_NO_ERROR { 46 | None 47 | } else { 48 | Some(Error(Repr::Raw(code))) 49 | } 50 | } 51 | 52 | /// Returns the raw error code that this error represents. 53 | #[inline] 54 | pub fn to_raw_error(&self) -> errcode_t { 55 | match self.0 { 56 | Repr::Simple(kind) => kind.to_raw_error(), 57 | Repr::Raw(code) => code, 58 | } 59 | } 60 | 61 | /// Returns the corresponding [`ErrorKind`] for this error (if any). 62 | /// 63 | /// [`ErrorKind`]: ./enum.ErrorKind.html 64 | #[inline] 65 | pub fn kind(&self) -> Option { 66 | match self.0 { 67 | Repr::Simple(kind) => Some(kind), 68 | Repr::Raw(code) => ErrorKind::from_raw_error(code), 69 | } 70 | } 71 | } 72 | 73 | impl Display for Error { 74 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 75 | use Repr::*; 76 | match self.0 { 77 | Simple(kind) => write!(f, "{}", kind), 78 | Raw(code) => { 79 | if let Some(kind) = ErrorKind::from_raw_error(code) { 80 | write!(f, "{}", kind) 81 | } else { 82 | write!(f, "unknown error code: {}", code) 83 | } 84 | } 85 | } 86 | } 87 | } 88 | 89 | impl std::error::Error for Error {} 90 | 91 | impl From for Error { 92 | #[inline] 93 | fn from(e: ErrorKind) -> Self { 94 | Error(Repr::Simple(e)) 95 | } 96 | } 97 | 98 | impl ErrorKind { 99 | #[inline] 100 | pub(crate) fn to_raw_error(&self) -> errcode_t { 101 | use ErrorKind::*; 102 | match *self { 103 | TypeError => sys::LIBRARY_TYPE_ERROR, 104 | RankError => sys::LIBRARY_RANK_ERROR, 105 | DimensionError => sys::LIBRARY_DIMENSION_ERROR, 106 | NumericalError => sys::LIBRARY_NUMERICAL_ERROR, 107 | MemoryError => sys::LIBRARY_MEMORY_ERROR, 108 | FunctionError => sys::LIBRARY_FUNCTION_ERROR, 109 | VersionError => sys::LIBRARY_VERSION_ERROR, 110 | } 111 | } 112 | 113 | #[inline] 114 | pub(crate) fn from_raw_error(code: errcode_t) -> Option { 115 | use ErrorKind::*; 116 | match code { 117 | sys::LIBRARY_NO_ERROR => unreachable!(), 118 | sys::LIBRARY_TYPE_ERROR => Some(TypeError), 119 | sys::LIBRARY_RANK_ERROR => Some(RankError), 120 | sys::LIBRARY_DIMENSION_ERROR => Some(DimensionError), 121 | sys::LIBRARY_NUMERICAL_ERROR => Some(NumericalError), 122 | sys::LIBRARY_MEMORY_ERROR => Some(MemoryError), 123 | sys::LIBRARY_FUNCTION_ERROR => Some(FunctionError), 124 | sys::LIBRARY_VERSION_ERROR => Some(VersionError), 125 | _ => None, 126 | } 127 | } 128 | } 129 | 130 | impl Display for ErrorKind { 131 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 132 | use ErrorKind::*; 133 | match *self { 134 | TypeError => write!(f, "unexpected type encountered"), 135 | RankError => write!(f, "unexpected rank encountered "), 136 | DimensionError => write!(f, "inconsistent dimensions encountered"), 137 | NumericalError => write!(f, "error in numerical computation"), 138 | MemoryError => write!(f, "problem allocating memory"), 139 | FunctionError => write!(f, "generic error from a function"), 140 | VersionError => write!(f, "incompatible version"), 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Procedural macros for `wll`. 2 | 3 | extern crate proc_macro; 4 | 5 | use crate::proc_macro::TokenStream; 6 | use quote::{format_ident, quote, quote_spanned, ToTokens}; 7 | use syn::spanned::Spanned; 8 | use syn::{ 9 | parse_macro_input, AttributeArgs, FnArg, ItemFn, Lit, LitInt, Meta, NestedMeta, ReturnType, 10 | Signature, 11 | }; 12 | 13 | /// Mark the function as the initialization function for Wolfram LibraryLink. 14 | /// 15 | /// **see also**: [Library Structure and Life Cycle: Initialization](https://reference.wolfram.com/language/LibraryLink/tutorial/LibraryStructure.html#280210622) 16 | #[proc_macro_attribute] 17 | pub fn setup(_args: TokenStream, input: TokenStream) -> TokenStream { 18 | let ast = parse_macro_input!(input as ItemFn); 19 | let funcall = match &ast.sig { 20 | Signature { 21 | ident: id, 22 | inputs: params, 23 | asyncness: None, 24 | unsafety: None, 25 | variadic: None, 26 | output: ret, 27 | .. 28 | } if params.is_empty() => { 29 | if let ReturnType::Type(_, ty) = ret { 30 | quote_spanned! { ty.span() => 31 | if let ::std::result::Result::Err(e) = #id() { 32 | return e.to_raw_error(); 33 | } 34 | } 35 | } else { 36 | quote_spanned! { id.span() => #id() } 37 | } 38 | } 39 | sig => invalid_function_signature(sig.span()), 40 | }; 41 | (quote! { 42 | #[inline(always)] 43 | #ast 44 | #[no_mangle] 45 | pub extern "C" fn WolframLibrary_initialize( 46 | data: ::wll::sys::WolframLibraryData 47 | ) -> ::wll::sys::errcode_t { 48 | if let ::std::result::Result::Err(e) = ::wll::global::initialize_lib_data(data) { 49 | e.to_raw_error() 50 | } else { 51 | #funcall; 52 | ::wll::sys::LIBRARY_NO_ERROR 53 | } 54 | } 55 | #[no_mangle] 56 | pub extern "C" fn WolframLibrary_getVersion() -> ::wll::sys::mint { 57 | ::wll::sys::WolframLibraryVersion 58 | } 59 | }) 60 | .into() 61 | } 62 | 63 | /// Mark the function as the uninitialization function for Wolfram LibraryLink. 64 | /// 65 | /// **see also**: [Library Structure and Life Cycle: Uninitialization](https://reference.wolfram.com/language/LibraryLink/tutorial/LibraryStructure.html#441777402) 66 | #[proc_macro_attribute] 67 | pub fn teardown(_args: TokenStream, input: TokenStream) -> TokenStream { 68 | let ast = parse_macro_input!(input as ItemFn); 69 | let funcall = match &ast.sig { 70 | Signature { 71 | ident: id, 72 | inputs: params, 73 | asyncness: None, 74 | unsafety: None, 75 | variadic: None, 76 | output: ReturnType::Default, 77 | .. 78 | } if params.is_empty() => quote_spanned! { id.span() => #id() }, 79 | sig => invalid_function_signature(sig.span()), 80 | }; 81 | (quote! { 82 | #[inline(always)] 83 | #ast 84 | #[no_mangle] 85 | pub extern "C" fn WolframLibrary_uninitialize( 86 | _: ::wll::sys::WolframLibraryData 87 | ) { 88 | #funcall; 89 | } 90 | }) 91 | .into() 92 | } 93 | 94 | /// Export function for Wolfram LibraryLink. 95 | /// 96 | /// **see also**: [Library Structure and Life Cycle: Functions, Arguments, and Results](https://reference.wolfram.com/language/LibraryLink/tutorial/LibraryStructure.html#606935091) 97 | #[proc_macro_attribute] 98 | pub fn export(args: TokenStream, input: TokenStream) -> TokenStream { 99 | let args = parse_macro_input!(args as AttributeArgs); 100 | let input = parse_macro_input!(input as ItemFn); 101 | let Signature { 102 | ident: funame, 103 | inputs: params, 104 | paren_token: sig_paren, 105 | .. 106 | } = &input.sig; 107 | let exportname = match args.len() { 108 | 0 => format_ident!("wll_{}", funame).into_token_stream(), 109 | _ => get_export_name_from_meta(&args[0]), 110 | }; 111 | let paramc = params.len(); 112 | let paramclit = LitInt::new(¶mc.to_string(), sig_paren.span); 113 | let argvars = (0..paramc).map(|i| format_ident!("arg{:o}", i)); 114 | let argvars2 = argvars.clone(); 115 | let arggets = params.iter().enumerate().map(|(i, arg)| match arg { 116 | FnArg::Receiver(recr) => invalid_function_signature(recr.span()), 117 | FnArg::Typed(pty) => { 118 | let ty = &pty.ty; 119 | let inner = quote_spanned! { ty.span() => 120 | <#ty>::try_get_arg(args.add(#i).read()) 121 | }; 122 | unwrap_errcode(inner, ty.span()) 123 | } 124 | }); 125 | let (funcall, setres) = match &input.sig { 126 | Signature { 127 | asyncness: None, 128 | variadic: None, 129 | output: ReturnType::Type(_, ty), 130 | .. 131 | } => { 132 | let inner = quote_spanned! { input.sig.span() => 133 | #funame(#(#argvars2),*) 134 | }; 135 | let setres = quote_spanned! { ty.span() => 136 | match ret.try_set_arg(&res) { 137 | ::std::result::Result::Ok(()) => ::wll::sys::LIBRARY_NO_ERROR, 138 | ::std::result::Result::Err(err) => err.to_raw_error(), 139 | } 140 | }; 141 | (unwrap_errcode(inner, ty.span()), setres) 142 | } 143 | sig => ( 144 | invalid_function_signature(sig.span()), 145 | invalid_function_signature(sig.span()), 146 | ), 147 | }; 148 | (quote! { 149 | #[inline] 150 | #input 151 | #[no_mangle] 152 | pub unsafe extern "C" fn #exportname( 153 | lib_data: ::wll::sys::WolframLibraryData, 154 | argc: ::wll::sys::mint, 155 | args: *const ::wll::sys::MArgument, 156 | res: ::wll::sys::MArgument, 157 | ) -> ::wll::sys::errcode_t { 158 | use ::wll::adaptor::{MArgumentGetter, MArgumentSetter}; 159 | let _lib_data = ::wll::global::LibDataLocalizer::new(lib_data); 160 | if argc != #paramclit { 161 | return ::wll::sys::LIBRARY_TYPE_ERROR; 162 | } 163 | #(let #argvars = #arggets;)* 164 | let ret = #funcall; 165 | #setres 166 | } 167 | }) 168 | .into() 169 | } 170 | 171 | fn get_export_name_from_meta(meta: &NestedMeta) -> proc_macro2::TokenStream { 172 | match meta { 173 | NestedMeta::Meta(Meta::Path(path)) => { 174 | if let Some(ident) = path.get_ident() { 175 | ident.to_token_stream() 176 | } else { 177 | syn::Error::new(path.span(), "expected identifier for export name.") 178 | .to_compile_error() 179 | } 180 | } 181 | NestedMeta::Lit(Lit::Str(str)) => match str.parse::() { 182 | Ok(ident) => ident.into_token_stream(), 183 | Err(e) => e.to_compile_error(), 184 | }, 185 | other => { 186 | syn::Error::new(other.span(), "expected identifier for export name.").to_compile_error() 187 | } 188 | } 189 | } 190 | 191 | fn unwrap_errcode( 192 | expr: proc_macro2::TokenStream, 193 | span: proc_macro2::Span, 194 | ) -> proc_macro2::TokenStream { 195 | quote_spanned! { span => 196 | match #expr { 197 | ::std::result::Result::Ok(val) => val, 198 | ::std::result::Result::Err(err) => return err.to_raw_error(), 199 | } 200 | } 201 | } 202 | 203 | fn invalid_function_signature(span: proc_macro2::Span) -> proc_macro2::TokenStream { 204 | syn::Error::new(span, "invalid function signature!").to_compile_error() 205 | } 206 | -------------------------------------------------------------------------------- /sys/include/WolframLibrary.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | Mathematica source file 3 | 4 | Copyright 1986 through 2015 by Wolfram Research Inc. 5 | 6 | This material contains trade secrets and may be registered with the 7 | U.S. Copyright Office as an unpublished work, pursuant to Title 17, 8 | U.S. Code, Section 408. Unauthorized copying, adaptation, distribution 9 | or display is prohibited. 10 | 11 | $Id: WolframLibrary.h,v 1.65 2014/09/30 15:03:51 marks Exp $ 12 | 13 | *************************************************************************/ 14 | 15 | #ifndef WOLFRAMLIBRARY_H 16 | #define WOLFRAMLIBRARY_H 17 | 18 | // #include "setjmp.h" 19 | 20 | #define WolframLibraryVersion 6 21 | 22 | #if !(defined(MATHEMATICA_KERNEL) || defined(MATHEMATICA_RUNTIME)) 23 | 24 | #include 25 | #include 26 | #include "dllexport.h" 27 | #include "extern.h" 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | #define True 1 34 | #define False 0 35 | 36 | #ifdef MINT_32 37 | typedef int32_t mint; 38 | typedef uint32_t umint; 39 | #else 40 | typedef int64_t mint; 41 | typedef uint64_t umint; 42 | #endif 43 | 44 | typedef int mbool; 45 | 46 | typedef double mreal; 47 | 48 | typedef int type_t; 49 | 50 | typedef int errcode_t; 51 | 52 | typedef uint32_t UBIT32; 53 | 54 | typedef uint64_t UBIT64; 55 | 56 | /* Platform specific variants in mcomplex.h */ 57 | 58 | typedef struct {mreal ri[2];} mcomplex; 59 | 60 | #define mcreal(z) (((z).ri)[0]) 61 | #define mcimag(z) (((z).ri)[1]) 62 | 63 | /* Incomplete types */ 64 | 65 | typedef struct st_MTensor *MTensor; 66 | 67 | typedef struct st_MNumericArray *MRawArray; 68 | 69 | typedef struct st_MNumericArray *MNumericArray; 70 | 71 | typedef struct MSparseArray_struct *MSparseArray; 72 | 73 | typedef struct IMAGEOBJ_ENTRY *MImage; 74 | 75 | /* Hard-coded types for CYINTEGER, CYREAL CYCOMPLEX */ 76 | 77 | #define MType_Integer 2 78 | #define MType_Real 3 79 | #define MType_Complex 4 80 | 81 | typedef union { 82 | mbool *boolean; 83 | mint *integer; 84 | mreal *real; 85 | mcomplex *cmplex; 86 | MTensor *tensor; 87 | MSparseArray *sparse; 88 | MNumericArray *numeric; 89 | MImage *image; 90 | char **utf8string; 91 | } MArgument; 92 | 93 | #define MArgument_getBooleanAddress(marg) ((marg).boolean) 94 | #define MArgument_getIntegerAddress(marg) ((marg).integer) 95 | #define MArgument_getRealAddress(marg) ((marg).real) 96 | #define MArgument_getComplexAddress(marg) ((marg).cmplex) 97 | #define MArgument_getMTensorAddress(marg) ((marg).tensor) 98 | #define MArgument_getMSparseArrayAddress(marg) ((marg).sparse) 99 | #define MArgument_getMRawArrayAddress(marg) ((marg).numeric) 100 | #define MArgument_getMNumericArrayAddress(marg) ((marg).numeric) 101 | #define MArgument_getMImageAddress(marg) ((marg).image) 102 | #define MArgument_getUTF8StringAddress(marg) ((marg).utf8string) 103 | 104 | #define MArgument_getAddress(marg) ((void *) ((marg).integer)) 105 | #define MArgument_setAddress(marg, add) (((marg).integer) = ((mint *) (add))) 106 | 107 | #define MArgument_getBoolean(marg) (*MArgument_getBooleanAddress(marg)) 108 | #define MArgument_getInteger(marg) (*MArgument_getIntegerAddress(marg)) 109 | #define MArgument_getReal(marg) (*MArgument_getRealAddress(marg)) 110 | #define MArgument_getComplex(marg) (*MArgument_getComplexAddress(marg)) 111 | #define MArgument_getMTensor(marg) (*MArgument_getMTensorAddress(marg)) 112 | #define MArgument_getMSparseArray(marg) (*MArgument_getMSparseArrayAddress(marg)) 113 | #define MArgument_getMRawArray(marg) (*MArgument_getMRawArrayAddress(marg)) 114 | #define MArgument_getMNumericArray(marg) (*MArgument_getMNumericArrayAddress(marg)) 115 | #define MArgument_getMImage(marg) (*MArgument_getMImageAddress(marg)) 116 | #define MArgument_getUTF8String(marg) (*MArgument_getUTF8StringAddress(marg)) 117 | 118 | #define MArgument_setBoolean(marg, v) ((*MArgument_getBooleanAddress(marg)) = (v)) 119 | #define MArgument_setInteger(marg, v) ((*MArgument_getIntegerAddress(marg)) = (v)) 120 | #define MArgument_setReal(marg, v) ((*MArgument_getRealAddress(marg)) = (v)) 121 | #define MArgument_setComplex(marg, v) ((*MArgument_getComplexAddress(marg)) = (v)) 122 | #define MArgument_setMTensor(marg, v) ((*MArgument_getMTensorAddress(marg)) = (v)) 123 | #define MArgument_setMSparseArray(marg, v) ((*MArgument_getMSparseArrayAddress(marg)) = (v)) 124 | #define MArgument_setMRawArray(marg, v) ((*MArgument_getMRawArrayAddress(marg)) = (v)) 125 | #define MArgument_setMNumericArray(marg, v) ((*MArgument_getMNumericArrayAddress(marg)) = (v)) 126 | #define MArgument_setMImage(marg, v) ((*MArgument_getMImageAddress(marg)) = (v)) 127 | #define MArgument_setUTF8String(marg, v) ((*MArgument_getUTF8StringAddress(marg)) = (v)) 128 | 129 | #ifdef __cplusplus 130 | } 131 | #endif 132 | 133 | #endif /* !(defined(MATHEMATICA_KERNEL) || defined(MATHEMATICA_RUNTIME)) */ 134 | 135 | #ifdef __cplusplus 136 | extern "C" { 137 | #endif 138 | 139 | #if defined(_MATHLINK_H) 140 | 141 | #define WSLINK MLINK 142 | #define WSENV MLENV 143 | 144 | #else 145 | 146 | #ifndef __MLINK__ 147 | typedef struct MLink *MLINK; 148 | typedef struct MLink *WSLINK; 149 | #define __MLINK__ 150 | #endif 151 | 152 | #ifndef __MLENV__ 153 | typedef struct ml_environment *MLENV; 154 | typedef MLENV MLEnvironment; 155 | typedef struct ml_environment *WSENV; 156 | typedef WSENV WSEnvironment; 157 | #define __MLENV__ 158 | #endif 159 | 160 | #endif /* defined(_MATHLINK_H) */ 161 | 162 | #ifndef MSTREAM_TYPEDEF 163 | #define MSTREAM_TYPEDEF 164 | typedef struct st_MInputStream *MInputStream; 165 | typedef struct st_MOutputStream *MOutputStream; 166 | #endif 167 | 168 | /* Error types for LibraryErrorHandler */ 169 | enum { 170 | LIBRARY_NO_ERROR = 0, 171 | LIBRARY_TYPE_ERROR, 172 | LIBRARY_RANK_ERROR, 173 | LIBRARY_DIMENSION_ERROR, 174 | LIBRARY_NUMERICAL_ERROR, 175 | LIBRARY_MEMORY_ERROR, 176 | LIBRARY_FUNCTION_ERROR, 177 | LIBRARY_VERSION_ERROR 178 | }; 179 | 180 | typedef struct st_DataStore *DataStore; 181 | 182 | 183 | 184 | typedef struct st_WolframLibraryData* WolframLibraryData; 185 | 186 | /* For backward compatibility with name change */ 187 | #define getMathLink getWSLINK 188 | #define processMathLink processWSLINK 189 | #define getMathLinkEnvironment getWSLINKEnvironment 190 | 191 | struct st_WolframLibraryData 192 | { 193 | void (*UTF8String_disown)(char *); 194 | 195 | int (*MTensor_new)(mint, mint, mint const*, MTensor *); 196 | void (*MTensor_free)( MTensor); 197 | int (*MTensor_clone)( MTensor, MTensor *); 198 | mint (*MTensor_shareCount)(MTensor); 199 | void (*MTensor_disown)( MTensor); 200 | void (*MTensor_disownAll)(MTensor); 201 | 202 | int (*MTensor_setInteger)(MTensor, mint*, mint); 203 | int (*MTensor_setReal)(MTensor, mint*, mreal); 204 | int (*MTensor_setComplex)(MTensor, mint*, mcomplex); 205 | int (*MTensor_setMTensor)(MTensor, MTensor, mint*, mint); 206 | 207 | int (*MTensor_getInteger)(MTensor, mint *, mint *); 208 | int (*MTensor_getReal)(MTensor, mint *, mreal *); 209 | int (*MTensor_getComplex)(MTensor, mint *, mcomplex *); 210 | int (*MTensor_getMTensor)(MTensor, mint *, mint, MTensor *); 211 | 212 | mint (*MTensor_getRank)( MTensor); 213 | mint const * (*MTensor_getDimensions)( MTensor); 214 | mint (*MTensor_getType)( MTensor); 215 | mint (*MTensor_getFlattenedLength)( MTensor); 216 | mint* (*MTensor_getIntegerData)( MTensor); 217 | mreal* (*MTensor_getRealData)( MTensor); 218 | mcomplex* (*MTensor_getComplexData)( MTensor); 219 | void (*Message)(const char *); 220 | mint (*AbortQ)(void); 221 | WSLINK (*getWSLINK)(WolframLibraryData); 222 | int (*processWSLINK)(WSLINK); 223 | int (*evaluateExpression)(WolframLibraryData, char *, int, mint, void *); 224 | struct st_WolframRuntimeData *runtimeData; 225 | struct st_WolframCompileLibrary_Functions *compileLibraryFunctions; 226 | mint VersionNumber; 227 | 228 | /* Added in WolframLibraryVersion 2 */ 229 | mbool (*registerInputStreamMethod)( 230 | const char *name, 231 | void (*ctor)(MInputStream, const char* msgHead, void* optionsIn), 232 | mbool (*handlerTest)(void*, char*), 233 | void* methodData, 234 | void (*destroyMethod)(void* methodData) 235 | ); 236 | 237 | mbool (*unregisterInputStreamMethod)(const char *name); 238 | 239 | mbool (*registerOutputStreamMethod)( 240 | const char *name, 241 | void (*ctor)(MOutputStream, const char* msgHead, void* optionsIn, mbool appendMode), 242 | mbool (*handlerTest)(void*, char*), 243 | void* methodData, 244 | void (*destroyMethod)(void* methodData) 245 | ); 246 | 247 | mbool (*unregisterOutputStreamMethod)(const char *name); 248 | 249 | struct st_WolframIOLibrary_Functions* ioLibraryFunctions; 250 | WSENV (*getWSLINKEnvironment)(WolframLibraryData); 251 | struct st_WolframSparseLibrary_Functions *sparseLibraryFunctions; 252 | struct st_WolframImageLibrary_Functions *imageLibraryFunctions; 253 | 254 | int (*registerLibraryExpressionManager)(const char *mname, void (*mfun)(WolframLibraryData, mbool, mint)); 255 | int (*unregisterLibraryExpressionManager)(const char *mname); 256 | int (*releaseManagedLibraryExpression)(const char *mname, mint id); 257 | 258 | int (*registerLibraryCallbackManager)(const char *name, mbool (*mfun)(WolframLibraryData, mint, MTensor)); 259 | int (*unregisterLibraryCallbackManager)(const char *name); 260 | int (*callLibraryCallbackFunction)(mint id, mint ArgC, MArgument *Args, MArgument Res); 261 | int (*releaseLibraryCallbackFunction)(mint id); 262 | 263 | /* security callback */ 264 | mbool (*validatePath)(char* path, char type); 265 | mbool (*protectedModeQ)(void); 266 | 267 | struct st_WolframRawArrayLibrary_Functions *rawarrayLibraryFunctions; 268 | struct st_WolframNumericArrayLibrary_Functions *numericarrayLibraryFunctions; 269 | 270 | /* 271 | Sets the value ParallelThreadNumber and returns the old value, or the input if invalid. 272 | The old value should be stored in a local variable. 273 | The old value must be restored using restoreParallelThreadNumber 274 | before the setting routine exits. 275 | */ 276 | int (*setParallelThreadNumber)(int); 277 | void (*restoreParallelThreadNumber)(int); 278 | int (*getParallelThreadNumber)(void); 279 | }; 280 | 281 | #ifdef __cplusplus 282 | } 283 | #endif 284 | 285 | #endif 286 | -------------------------------------------------------------------------------- /src/adaptor.rs: -------------------------------------------------------------------------------- 1 | //! Some adaptor interface for Wolfram LibraryLink. 2 | 3 | use crate::{Complex, ErrorKind, Result}; 4 | use std::convert::TryInto; 5 | use std::num::Wrapping; 6 | use sys::{mbool, mcomplex, mint, mreal, MArgument, MImage, MNumericArray, MSparseArray, MTensor}; 7 | 8 | mod private { 9 | pub trait Sealed {} 10 | } 11 | 12 | /// Basic trait for Wolfram LibraryLink underlying type. 13 | /// Typically doesn’t need to be used directly. 14 | /// 15 | /// You **CANNOT** implement it outside. 16 | pub trait MType: private::Sealed + Sized {} 17 | 18 | macro_rules! impl_mtypes { 19 | ($($t:ty),+) => { 20 | $( 21 | impl private::Sealed for $t {} 22 | impl MType for $t {} 23 | )+ 24 | }; 25 | } 26 | 27 | impl_mtypes!( 28 | mbool, 29 | mint, 30 | mreal, 31 | mcomplex, 32 | MTensor, 33 | MSparseArray, 34 | MNumericArray, 35 | MImage 36 | ); 37 | 38 | // `MType` or `()`. 39 | #[doc(hidden)] 40 | pub trait MTypeOrVoid: private::Sealed {} 41 | 42 | impl MTypeOrVoid for T {} 43 | impl private::Sealed for () {} 44 | impl MTypeOrVoid for () {} 45 | 46 | /// Adaptor for [`MType`] input. 47 | /// 48 | /// [`MType`]: ./trait.MType.html 49 | pub trait InputAdaptor: Sized { 50 | /// Input type. 51 | type Input: MType; 52 | 53 | /// Performs the conversion. 54 | fn mtype_try_from(input: Self::Input) -> Result; 55 | } 56 | 57 | /// Adaptor for [`MType`] output. 58 | /// 59 | /// [`MType`]: ./trait.MType.html 60 | pub trait OutputAdaptor: Sized { 61 | /// Output type. 62 | type Output: MType; 63 | 64 | /// Performs the conversion. 65 | fn try_into_mtype(self) -> Result; 66 | } 67 | 68 | // Adaptor trait for getting `MArgument`. 69 | // Typically doesn’t need to be used directly. 70 | // 71 | // `MArgumentGetter` will be implemented automatically if proper `InputAdaptor` has been implemented. 72 | // 73 | // **DO NOT** implement this trait yourself. 74 | #[doc(hidden)] 75 | pub trait MArgumentGetter: Sized { 76 | /// Try to get `MArgument`. 77 | fn try_get_arg(arg: MArgument) -> Result; 78 | } 79 | 80 | // Adaptor trait for setting `MArgument`. 81 | // Typically doesn’t need to be used directly. 82 | // 83 | // `MArgumentSetter` will be implemented automatically if proper `OutputAdaptor` has been implemented. 84 | // 85 | // **DO NOT** implement this trait yourself. 86 | #[doc(hidden)] 87 | pub trait MArgumentSetter: Sized { 88 | /// Try to set `MArgument`. 89 | fn try_set_arg(self, arg: &MArgument) -> Result<()>; 90 | } 91 | 92 | impl MArgumentSetter<()> for () { 93 | #[inline] 94 | fn try_set_arg(self, _arg: &MArgument) -> Result<()> { 95 | Ok(()) 96 | } 97 | } 98 | 99 | macro_rules! impl_argument_getter { 100 | ($fd:ident: $t:ty) => { 101 | impl> MArgumentGetter<$t> for T { 102 | #[inline] 103 | fn try_get_arg(arg: MArgument) -> Result { 104 | unsafe { 105 | let ptr = arg.$fd; 106 | if ptr.is_null() { 107 | return Err(ErrorKind::TypeError.into()); 108 | } 109 | T::mtype_try_from(std::ptr::read(ptr)) 110 | } 111 | } 112 | } 113 | }; 114 | } 115 | 116 | macro_rules! impl_argument_setter { 117 | ($fd:ident: $t:ty) => { 118 | impl> MArgumentSetter<$t> for T { 119 | #[inline] 120 | fn try_set_arg(self, arg: &MArgument) -> Result<()> { 121 | unsafe { 122 | let ptr = arg.$fd; 123 | if ptr.is_null() { 124 | return Err(ErrorKind::TypeError.into()); 125 | } 126 | std::ptr::write(ptr, self.try_into_mtype()?); 127 | } 128 | Ok(()) 129 | } 130 | } 131 | }; 132 | } 133 | 134 | macro_rules! impl_argument_getter_setter { 135 | {$($fd:ident: $t:ty,)*} => { 136 | $( 137 | impl_argument_getter!($fd: $t); 138 | impl_argument_setter!($fd: $t); 139 | )* 140 | }; 141 | } 142 | 143 | impl_argument_getter_setter! { 144 | boolean: mbool, 145 | integer: mint, 146 | real: mreal, 147 | cmplex: mcomplex, 148 | tensor: MTensor, 149 | sparse: MSparseArray, 150 | numeric: MNumericArray, 151 | image: MImage, 152 | } 153 | 154 | impl InputAdaptor for bool { 155 | type Input = mbool; 156 | 157 | #[inline] 158 | fn mtype_try_from(input: Self::Input) -> Result { 159 | Ok(input != sys::False) 160 | } 161 | } 162 | 163 | impl OutputAdaptor for bool { 164 | type Output = mbool; 165 | 166 | #[inline] 167 | fn try_into_mtype(self) -> Result { 168 | Ok(if self { sys::True } else { sys::False }) 169 | } 170 | } 171 | 172 | macro_rules! impl_int_adaptor { 173 | ($($t:ty),+) => { 174 | $( 175 | impl InputAdaptor for $t { 176 | type Input = mint; 177 | 178 | #[inline] 179 | fn mtype_try_from(input: Self::Input) -> Result { 180 | input 181 | .try_into() 182 | .map_err(|_| ErrorKind::TypeError.into()) 183 | } 184 | } 185 | impl OutputAdaptor for $t { 186 | type Output = mint; 187 | 188 | #[inline] 189 | fn try_into_mtype(self) -> Result { 190 | self.try_into() 191 | .map_err(|_| ErrorKind::TypeError.into()) 192 | } 193 | } 194 | )+ 195 | } 196 | } 197 | 198 | impl_int_adaptor!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); 199 | 200 | macro_rules! impl_wrapping_int_adaptor { 201 | ($($t:ty),+) => { 202 | $( 203 | impl InputAdaptor for Wrapping<$t> { 204 | type Input = mint; 205 | 206 | #[inline] 207 | fn mtype_try_from(input: Self::Input) -> Result { 208 | Ok(Wrapping(<$t>::mtype_try_from(input)?)) 209 | } 210 | } 211 | impl OutputAdaptor for Wrapping<$t> { 212 | type Output = mint; 213 | 214 | #[inline] 215 | fn try_into_mtype(self) -> Result { 216 | self.0.try_into_mtype() 217 | } 218 | } 219 | )+ 220 | }; 221 | } 222 | 223 | impl_wrapping_int_adaptor!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); 224 | 225 | macro_rules! impl_real_adaptor { 226 | ($($t:ty),+) => { 227 | $( 228 | impl InputAdaptor for $t { 229 | type Input = mreal; 230 | 231 | fn mtype_try_from(input: Self::Input) -> Result { 232 | Ok(input as Self) 233 | } 234 | } 235 | impl OutputAdaptor for $t { 236 | type Output = mreal; 237 | 238 | fn try_into_mtype(self) -> Result { 239 | Ok(self as Self::Output) 240 | } 241 | } 242 | )+ 243 | }; 244 | } 245 | 246 | impl_real_adaptor!(f32, f64); 247 | 248 | macro_rules! impl_complex_real_adaptor { 249 | ($($t:ty),+) => { 250 | $( 251 | impl InputAdaptor for Complex<$t> { 252 | type Input = mcomplex; 253 | 254 | #[inline] 255 | fn mtype_try_from(input: Self::Input) -> Result { 256 | Ok(Self::new(input.ri[0] as $t, input.ri[1] as $t)) 257 | } 258 | } 259 | impl OutputAdaptor for Complex<$t> { 260 | type Output = mcomplex; 261 | 262 | #[inline] 263 | fn try_into_mtype(self) -> Result { 264 | Ok(Self::Output { 265 | ri: [self.re as mreal, self.im as mreal], 266 | }) 267 | } 268 | } 269 | )+ 270 | }; 271 | } 272 | 273 | // Note: Complex can only be used in output. 274 | macro_rules! impl_complex_int_adaptor { 275 | ($($t:ty),+) => { 276 | $( 277 | impl OutputAdaptor for Complex<$t> { 278 | type Output = mcomplex; 279 | 280 | #[inline] 281 | fn try_into_mtype(self) -> Result { 282 | Ok(Self::Output { 283 | ri: [self.re as mreal, self.im as mreal], 284 | }) 285 | } 286 | } 287 | )+ 288 | }; 289 | } 290 | 291 | impl_complex_real_adaptor!(f32, f64); 292 | impl_complex_int_adaptor!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); 293 | 294 | #[cfg(test)] 295 | mod tests { 296 | use super::*; 297 | use std::mem::MaybeUninit; 298 | use sys::{mbool, MArgument}; 299 | 300 | #[test] 301 | fn bool_true_input() { 302 | assert_eq!(bool::mtype_try_from(sys::True), Ok(true)); 303 | } 304 | 305 | #[test] 306 | fn bool_false_input() { 307 | assert_eq!(bool::mtype_try_from(sys::False), Ok(false)); 308 | } 309 | 310 | #[test] 311 | fn bool_true_output() { 312 | assert_eq!(true.try_into_mtype(), Ok(sys::True)); 313 | } 314 | 315 | #[test] 316 | fn bool_false_output() { 317 | assert_eq!(false.try_into_mtype(), Ok(sys::False)); 318 | } 319 | 320 | #[test] 321 | fn bool_true_get() { 322 | let mut mb = sys::True; 323 | let arg = MArgument { boolean: &mut mb }; 324 | assert_eq!(bool::try_get_arg(arg), Ok(true)); 325 | } 326 | 327 | #[test] 328 | fn bool_false_get() { 329 | let mut mb = sys::False; 330 | let arg = MArgument { boolean: &mut mb }; 331 | assert_eq!(bool::try_get_arg(arg), Ok(false)); 332 | } 333 | 334 | #[test] 335 | fn bool_true_set() { 336 | let mut mb = MaybeUninit::::uninit(); 337 | let arg = MArgument { 338 | boolean: mb.as_mut_ptr(), 339 | }; 340 | let res = true.try_set_arg(&arg); 341 | let mb = unsafe { mb.assume_init() }; 342 | assert_eq!((mb, res), (sys::True, Ok(()))); 343 | } 344 | 345 | #[test] 346 | fn bool_false_set() { 347 | let mut mb = MaybeUninit::::uninit(); 348 | let arg = MArgument { 349 | boolean: mb.as_mut_ptr(), 350 | }; 351 | let res = false.try_set_arg(&arg); 352 | let mb = unsafe { mb.assume_init() }; 353 | assert_eq!((mb, res), (sys::False, Ok(()))); 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /src/complex.rs: -------------------------------------------------------------------------------- 1 | //! Complex numbers. 2 | 3 | use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; 4 | use std::fmt::Debug; 5 | 6 | /// Generic complex number. 7 | #[repr(C)] 8 | #[derive(PartialEq, Eq, Copy, Clone, Hash, Debug, Default)] 9 | pub struct Complex { 10 | /// Real part. 11 | pub re: T, 12 | /// Imaginary part. 13 | pub im: T, 14 | } 15 | 16 | impl Complex { 17 | /// Construct a new complex number. 18 | #[inline] 19 | pub const fn new(re: T, im: T) -> Self { 20 | Complex { re, im } 21 | } 22 | } 23 | 24 | impl From for Complex 25 | where 26 | T: Default, 27 | { 28 | #[inline] 29 | fn from(re: T) -> Self { 30 | Self::new(re, T::default()) 31 | } 32 | } 33 | 34 | impl<'a, T> From<&'a T> for Complex 35 | where 36 | T: Clone + Default, 37 | { 38 | #[inline] 39 | fn from(re: &T) -> Self { 40 | From::from(re.clone()) 41 | } 42 | } 43 | 44 | // -- Unary Operator -- 45 | 46 | impl Complex 47 | where 48 | T: Clone + Add + Mul, 49 | { 50 | /// Returns the square of the norm. 51 | #[inline] 52 | pub fn norm_sqr(&self) -> T { 53 | self.re.clone() * self.re.clone() + self.im.clone() * self.im.clone() 54 | } 55 | } 56 | 57 | impl Complex 58 | where 59 | T: Clone + Neg, 60 | { 61 | /// Returns the complex conjugate. 62 | #[inline] 63 | pub fn conj(&self) -> Self { 64 | Self::new(self.re.clone(), -self.im.clone()) 65 | } 66 | } 67 | 68 | impl Neg for Complex 69 | where 70 | T: Neg, 71 | { 72 | type Output = Self; 73 | 74 | #[inline] 75 | fn neg(self) -> Self::Output { 76 | Self::Output::new(-self.re, -self.im) 77 | } 78 | } 79 | 80 | impl<'a, T> Neg for &'a Complex 81 | where 82 | T: Clone + Neg, 83 | { 84 | type Output = Complex; 85 | 86 | #[inline] 87 | fn neg(self) -> Self::Output { 88 | -self.clone() 89 | } 90 | } 91 | 92 | // -- Binary Operator -- 93 | 94 | impl Add> for Complex 95 | where 96 | T: Clone + Add, 97 | { 98 | type Output = Self; 99 | 100 | #[inline] 101 | fn add(self, rhs: Self) -> Self::Output { 102 | Self::Output::new(self.re + rhs.re, self.im + rhs.im) 103 | } 104 | } 105 | 106 | impl Sub> for Complex 107 | where 108 | T: Clone + Sub, 109 | { 110 | type Output = Self; 111 | 112 | #[inline] 113 | fn sub(self, rhs: Self) -> Self::Output { 114 | Self::Output::new(self.re - rhs.re, self.im - rhs.im) 115 | } 116 | } 117 | 118 | impl Mul> for Complex 119 | where 120 | T: Clone + Add + Sub + Mul, 121 | { 122 | type Output = Self; 123 | 124 | #[inline] 125 | fn mul(self, rhs: Self) -> Self::Output { 126 | let re = self.re.clone() * rhs.re.clone() - self.im.clone() * rhs.im.clone(); 127 | let im = self.re * rhs.im + self.im * rhs.re; 128 | Self::Output::new(re, im) 129 | } 130 | } 131 | 132 | impl Div> for Complex 133 | where 134 | T: Clone + Add + Sub + Mul + Div, 135 | { 136 | type Output = Self; 137 | 138 | #[inline] 139 | fn div(self, rhs: Self) -> Self::Output { 140 | let deno = rhs.norm_sqr(); 141 | let re = self.re.clone() * rhs.re.clone() + self.im.clone() * rhs.im.clone(); 142 | let im = self.im * rhs.re - self.re * rhs.im; 143 | Self::Output::new(re / deno.clone(), im / deno) 144 | } 145 | } 146 | 147 | macro_rules! forward_ref_ref_binop { 148 | (impl $tr:ident => $method:ident where $($reqs:ident),+) => { 149 | impl<'a, 'b, T> $tr<&'b Complex> for &'a Complex 150 | where 151 | T: Clone $(+ $reqs)+, 152 | { 153 | type Output = Complex; 154 | 155 | #[inline] 156 | fn $method(self, rhs: &'b Complex) -> Self::Output { 157 | self.clone().$method(rhs.clone()) 158 | } 159 | } 160 | }; 161 | } 162 | 163 | macro_rules! forward_val_ref_binop { 164 | (impl $tr:ident => $method:ident where $($reqs:ident),+) => { 165 | impl<'a, T> $tr> for &'a Complex 166 | where 167 | T: Clone $(+ $reqs)+, 168 | { 169 | type Output = Complex; 170 | 171 | #[inline] 172 | fn $method(self, rhs: Complex) -> Self::Output { 173 | self.clone().$method(rhs) 174 | } 175 | } 176 | }; 177 | } 178 | 179 | macro_rules! forward_ref_val_binop { 180 | (impl $tr:ident => $method:ident where $($reqs:ident),+) => { 181 | impl<'a, T> $tr<&'a Complex> for Complex 182 | where 183 | T: Clone $(+ $reqs)+, 184 | { 185 | type Output = Complex; 186 | 187 | #[inline] 188 | fn $method(self, rhs: &'a Complex) -> Self::Output { 189 | self.$method(rhs.clone()) 190 | } 191 | } 192 | }; 193 | } 194 | 195 | macro_rules! forward_all_binop { 196 | (impl $tr:ident => $method:ident where $($reqs:ident),+) => { 197 | forward_ref_ref_binop!(impl $tr => $method where $($reqs),+); 198 | forward_val_ref_binop!(impl $tr => $method where $($reqs),+); 199 | forward_ref_val_binop!(impl $tr => $method where $($reqs),+); 200 | }; 201 | } 202 | 203 | forward_all_binop!(impl Add => add where Add); 204 | forward_all_binop!(impl Sub => sub where Sub); 205 | forward_all_binop!(impl Mul => mul where Add, Sub, Mul); 206 | forward_all_binop!(impl Div => div where Add, Sub, Mul, Div); 207 | 208 | // Operator Assign 209 | 210 | impl AddAssign for Complex 211 | where 212 | T: AddAssign, 213 | { 214 | #[inline] 215 | fn add_assign(&mut self, rhs: Self) { 216 | self.re += rhs.re; 217 | self.im += rhs.im; 218 | } 219 | } 220 | 221 | impl SubAssign for Complex 222 | where 223 | T: SubAssign, 224 | { 225 | #[inline] 226 | fn sub_assign(&mut self, rhs: Self) { 227 | self.re -= rhs.re; 228 | self.im -= rhs.im; 229 | } 230 | } 231 | 232 | impl MulAssign for Complex 233 | where 234 | T: Clone + AddAssign + SubAssign + MulAssign, 235 | { 236 | #[allow(clippy::suspicious_op_assign_impl)] 237 | #[inline] 238 | fn mul_assign(&mut self, rhs: Self) { 239 | let mut imim = self.im.clone(); 240 | imim *= rhs.im.clone(); 241 | self.re *= rhs.re.clone(); 242 | self.re -= imim; 243 | let mut reim = self.re.clone(); 244 | reim *= rhs.im; 245 | self.im *= rhs.re; 246 | self.im += reim; 247 | } 248 | } 249 | 250 | impl DivAssign for Complex 251 | where 252 | T: Clone + AddAssign + SubAssign + MulAssign + DivAssign, 253 | { 254 | #[allow(clippy::suspicious_op_assign_impl)] 255 | #[inline] 256 | fn div_assign(&mut self, rhs: Self) { 257 | let mut rhs_im2 = rhs.im.clone(); 258 | rhs_im2 *= rhs.im.clone(); 259 | let mut deno = rhs.re.clone(); 260 | deno *= rhs.re.clone(); 261 | deno += rhs_im2; 262 | let mut imim = self.im.clone(); 263 | imim *= rhs.im.clone(); 264 | self.re *= rhs.re.clone(); 265 | self.re += imim; 266 | self.re /= deno.clone(); 267 | let mut reim = self.re.clone(); 268 | reim *= rhs.im; 269 | self.im *= rhs.re; 270 | self.im -= reim; 271 | self.im /= deno; 272 | } 273 | } 274 | 275 | #[cfg(all(test, not(feature = "num-complex-type")))] 276 | mod tests { 277 | use super::*; 278 | 279 | const EPS: f64 = 1e-10; 280 | 281 | #[test] 282 | fn convert_int() { 283 | assert_eq!(Complex::from(1), Complex::new(1, 0)); 284 | } 285 | 286 | #[test] 287 | fn convert_real() { 288 | assert_eq!(Complex::from(1.), Complex::new(1., 0.)); 289 | } 290 | 291 | #[test] 292 | fn norm_sqr_int() { 293 | assert_eq!(Complex::new(-5, 12).norm_sqr(), 169); 294 | } 295 | 296 | #[test] 297 | fn norm_sqr_real() { 298 | assert!((Complex::new(3.0, -4.0).norm_sqr() - 25f64).abs() <= EPS) 299 | } 300 | 301 | #[test] 302 | fn conj_int() { 303 | assert_eq!(Complex::new(-2, 1).conj(), Complex::new(-2, -1)); 304 | } 305 | 306 | #[test] 307 | fn conj_real() { 308 | let a = Complex::new(1.2, -3.1); 309 | let ca = a.conj(); 310 | let b = Complex::new(1.2f64, 3.1f64); 311 | assert!((ca.re - b.re).abs() <= EPS && (ca.im - b.im).abs() <= EPS) 312 | } 313 | 314 | #[test] 315 | fn add_complex_int() { 316 | let a = Complex::new(2, 1); 317 | let b = Complex::new(3, -7); 318 | let c = Complex::new(5, -6); 319 | assert_eq!(a + b, c); 320 | } 321 | 322 | #[test] 323 | fn add_complex_real() { 324 | let a = Complex::new(0.1, -3.7); 325 | let b = Complex::new(2.4, 1.48); 326 | let c = Complex::new(2.5f64, -2.22f64); 327 | let ab = a + b; 328 | assert!((ab.re - c.re).abs() <= EPS && (ab.im - c.im).abs() <= EPS); 329 | } 330 | 331 | #[test] 332 | fn sub_complex_int() { 333 | let a = Complex::new(2, 1); 334 | let b = Complex::new(3, -7); 335 | let c = Complex::new(-1, 8); 336 | assert_eq!(a - b, c); 337 | } 338 | 339 | #[test] 340 | fn sub_complex_real() { 341 | let a = Complex::new(0.1, -3.7); 342 | let b = Complex::new(2.4, 1.48); 343 | let c = Complex::new(-2.3f64, -5.18f64); 344 | let ab = a - b; 345 | assert!((ab.re - c.re).abs() <= EPS && (ab.im - c.im).abs() <= EPS); 346 | } 347 | 348 | #[test] 349 | fn mul_complex_int() { 350 | let a = Complex::new(2, 1); 351 | let b = Complex::new(3, -7); 352 | let c = Complex::new(13, -11); 353 | assert_eq!(a * b, c); 354 | } 355 | 356 | #[test] 357 | fn mul_complex_real() { 358 | let a = Complex::new(0.1, -3.7); 359 | let b = Complex::new(2.4, 1.48); 360 | let c = Complex::new(5.716f64, -8.732f64); 361 | let ab = a * b; 362 | assert!((ab.re - c.re).abs() <= EPS && (ab.im - c.im).abs() <= EPS); 363 | } 364 | 365 | #[test] 366 | fn div_complex_int() { 367 | let a = Complex::new(2, 1); 368 | let b = Complex::new(3, -7); 369 | let c = Complex::new(0, -3); 370 | assert_eq!(b / a, c); 371 | } 372 | 373 | #[test] 374 | fn div_complex_real() { 375 | let a = Complex::new(0.5, -1.2); 376 | let b = Complex::new(4.6, -0.9); 377 | let c = Complex::new(2f64, 3f64); 378 | let ab = b / a; 379 | assert!((ab.re - c.re).abs() <= EPS && (ab.im - c.im).abs() <= EPS); 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /examples/examples.nb: -------------------------------------------------------------------------------- 1 | Notebook[ 2 | { 3 | Cell[ 4 | CellGroupData[ 5 | { 6 | Cell[ 7 | TextData[ 8 | { 9 | ButtonBox[ 10 | "wll-rs", 11 | BaseStyle -> "Hyperlink", 12 | ButtonData -> {URL["https://github.com/miRoox/wll-rs"], None}, 13 | ButtonNote -> "https://github.com/miRoox/wll-rs" 14 | ], 15 | " examples" 16 | } 17 | ], 18 | "Title" 19 | ], 20 | Cell[ 21 | CellGroupData[ 22 | { 23 | Cell["Basic examples", "Section"], 24 | Cell[ 25 | BoxData[ 26 | RowBox[ 27 | { 28 | RowBox[ 29 | { 30 | "lib", 31 | "=", 32 | RowBox[ 33 | { 34 | "FileNameJoin", 35 | "@", 36 | RowBox[ 37 | { 38 | "{", 39 | RowBox[ 40 | { 41 | RowBox[{"NotebookDirectory", "[", "]"}], 42 | ",", 43 | "\"..\"", 44 | ",", 45 | "\"target\"", 46 | ",", 47 | "\"release\"", 48 | ",", 49 | "\"basic\"" 50 | } 51 | ], 52 | "}" 53 | } 54 | ] 55 | } 56 | ] 57 | } 58 | ], 59 | ";" 60 | } 61 | ] 62 | ], 63 | "Input", 64 | CellLabel -> "In[1]:=" 65 | ], 66 | Cell[ 67 | BoxData[ 68 | RowBox[ 69 | { 70 | RowBox[ 71 | { 72 | "add", 73 | "=", 74 | RowBox[ 75 | { 76 | "LibraryFunctionLoad", 77 | "[", 78 | RowBox[ 79 | { 80 | "lib", 81 | ",", 82 | "\"wll_add_two\"", 83 | ",", 84 | RowBox[{"{", RowBox[{"Integer", ",", "Integer"}], "}"}], 85 | ",", 86 | "Integer" 87 | } 88 | ], 89 | "]" 90 | } 91 | ] 92 | } 93 | ], 94 | ";" 95 | } 96 | ] 97 | ], 98 | "Input", 99 | CellLabel -> "In[2]:=" 100 | ], 101 | Cell[ 102 | CellGroupData[ 103 | { 104 | Cell[ 105 | BoxData[RowBox[{"add", "[", RowBox[{"1", ",", "2"}], "]"}]], 106 | "Input", 107 | CellLabel -> "In[3]:=" 108 | ], 109 | Cell[BoxData["3"], "Output", CellLabel -> "Out[3]="] 110 | }, 111 | Open 112 | ] 113 | ], 114 | Cell[ 115 | CellGroupData[ 116 | { 117 | Cell[ 118 | BoxData[ 119 | RowBox[ 120 | { 121 | "add", 122 | "[", 123 | RowBox[ 124 | {"1", ",", RowBox[{RowBox[{"2", "^", "63"}], "-", "1"}]} 125 | ], 126 | "]" 127 | } 128 | ] 129 | ], 130 | "Input", 131 | CellLabel -> "In[4]:=" 132 | ], 133 | Cell[ 134 | BoxData[ 135 | TemplateBox[ 136 | { 137 | "LibraryFunction", 138 | "numerr", 139 | "\"\:5f53\:8ba1\:7b97\:51fd\:6570 \\!\\(\\*RowBox[{\\\"\\\\\\\"wll_add_two\\\\\\\"\\\"}]\\) \:65f6\:ff0c\:78b0\:5230\:6570\:503c\:9519\:8bef.\"", 140 | 2, 141 | 4, 142 | 1, 143 | 16580194668087359179, 144 | "Local" 145 | }, 146 | "MessageTemplate" 147 | ] 148 | ], 149 | "Message", 150 | "MSG", 151 | CellLabel -> "\:6b63\:5728\:8ba1\:7b97In[4]:=" 152 | ], 153 | Cell[ 154 | BoxData[ 155 | RowBox[ 156 | { 157 | "LibraryFunctionError", 158 | "[", 159 | RowBox[{"\"LIBRARY_NUMERICAL_ERROR\"", ",", "4"}], 160 | "]" 161 | } 162 | ] 163 | ], 164 | "Output", 165 | CellLabel -> "Out[4]=" 166 | ] 167 | }, 168 | Open 169 | ] 170 | ], 171 | Cell[ 172 | CellGroupData[ 173 | { 174 | Cell[ 175 | BoxData[ 176 | RowBox[ 177 | { 178 | "add", 179 | "[", 180 | RowBox[ 181 | { 182 | RowBox[{"-", "1"}], 183 | ",", 184 | RowBox[{"-", RowBox[{"2", "^", "63"}]}] 185 | } 186 | ], 187 | "]" 188 | } 189 | ] 190 | ], 191 | "Input", 192 | CellLabel -> "In[5]:=" 193 | ], 194 | Cell[ 195 | BoxData[ 196 | TemplateBox[ 197 | { 198 | "LibraryFunction", 199 | "numerr", 200 | "\"\:5f53\:8ba1\:7b97\:51fd\:6570 \\!\\(\\*RowBox[{\\\"\\\\\\\"wll_add_two\\\\\\\"\\\"}]\\) \:65f6\:ff0c\:78b0\:5230\:6570\:503c\:9519\:8bef.\"", 201 | 2, 202 | 5, 203 | 2, 204 | 16580194668087359179, 205 | "Local" 206 | }, 207 | "MessageTemplate" 208 | ] 209 | ], 210 | "Message", 211 | "MSG", 212 | CellLabel -> "\:6b63\:5728\:8ba1\:7b97In[5]:=" 213 | ], 214 | Cell[ 215 | BoxData[ 216 | RowBox[ 217 | { 218 | "LibraryFunctionError", 219 | "[", 220 | RowBox[{"\"LIBRARY_NUMERICAL_ERROR\"", ",", "4"}], 221 | "]" 222 | } 223 | ] 224 | ], 225 | "Output", 226 | CellLabel -> "Out[5]=" 227 | ] 228 | }, 229 | Open 230 | ] 231 | ], 232 | Cell[ 233 | BoxData[ 234 | RowBox[ 235 | { 236 | RowBox[ 237 | { 238 | "fac", 239 | "=", 240 | RowBox[ 241 | { 242 | "LibraryFunctionLoad", 243 | "[", 244 | RowBox[ 245 | { 246 | "lib", 247 | ",", 248 | "\"wfactorial\"", 249 | ",", 250 | RowBox[{"{", "Integer", "}"}], 251 | ",", 252 | "Integer" 253 | } 254 | ], 255 | "]" 256 | } 257 | ] 258 | } 259 | ], 260 | ";" 261 | } 262 | ] 263 | ], 264 | "Input", 265 | CellLabel -> "In[6]:=" 266 | ], 267 | Cell[ 268 | CellGroupData[ 269 | { 270 | Cell[ 271 | BoxData[RowBox[{"fac", "[", RowBox[{"-", "1"}], "]"}]], 272 | "Input", 273 | CellLabel -> "In[7]:=" 274 | ], 275 | Cell[ 276 | BoxData[ 277 | TemplateBox[ 278 | { 279 | "LibraryFunction", 280 | "typerr", 281 | "\"\:5728\:8ba1\:7b97\:51fd\:6570 \\!\\(\\*RowBox[{\\\"\\\\\\\"wfactorial\\\\\\\"\\\"}]\\) \:7684\:8fc7\:7a0b\:4e2d\:78b0\:5230\:7531\:4e0d\:4e00\:81f4\:7c7b\:578b\:4ea7\:751f\:7684\:9519\:8bef.\"", 282 | 2, 283 | 7, 284 | 3, 285 | 16580194668087359179, 286 | "Local" 287 | }, 288 | "MessageTemplate" 289 | ] 290 | ], 291 | "Message", 292 | "MSG", 293 | CellLabel -> "\:6b63\:5728\:8ba1\:7b97In[7]:=" 294 | ], 295 | Cell[ 296 | BoxData[ 297 | RowBox[ 298 | { 299 | "LibraryFunctionError", 300 | "[", 301 | RowBox[{"\"LIBRARY_TYPE_ERROR\"", ",", "1"}], 302 | "]" 303 | } 304 | ] 305 | ], 306 | "Output", 307 | CellLabel -> "Out[7]=" 308 | ] 309 | }, 310 | Open 311 | ] 312 | ], 313 | Cell[ 314 | CellGroupData[ 315 | { 316 | Cell[ 317 | BoxData[RowBox[{"fac", "[", "0", "]"}]], 318 | "Input", 319 | CellLabel -> "In[8]:=" 320 | ], 321 | Cell[BoxData["1"], "Output", CellLabel -> "Out[8]="] 322 | }, 323 | Open 324 | ] 325 | ], 326 | Cell[ 327 | CellGroupData[ 328 | { 329 | Cell[ 330 | BoxData[RowBox[{"fac", "[", "10", "]"}]], 331 | "Input", 332 | CellLabel -> "In[9]:=" 333 | ], 334 | Cell[BoxData["3628800"], "Output", CellLabel -> "Out[9]="] 335 | }, 336 | Open 337 | ] 338 | ], 339 | Cell[ 340 | CellGroupData[ 341 | { 342 | Cell[ 343 | BoxData[RowBox[{"fac", "[", "21", "]"}]], 344 | "Input", 345 | CellLabel -> "In[10]:=" 346 | ], 347 | Cell[ 348 | BoxData[ 349 | TemplateBox[ 350 | { 351 | "LibraryFunction", 352 | "typerr", 353 | "\"\:5728\:8ba1\:7b97\:51fd\:6570 \\!\\(\\*RowBox[{\\\"\\\\\\\"wfactorial\\\\\\\"\\\"}]\\) \:7684\:8fc7\:7a0b\:4e2d\:78b0\:5230\:7531\:4e0d\:4e00\:81f4\:7c7b\:578b\:4ea7\:751f\:7684\:9519\:8bef.\"", 354 | 2, 355 | 10, 356 | 4, 357 | 16580194668087359179, 358 | "Local" 359 | }, 360 | "MessageTemplate" 361 | ] 362 | ], 363 | "Message", 364 | "MSG", 365 | CellLabel -> "\:6b63\:5728\:8ba1\:7b97In[10]:=" 366 | ], 367 | Cell[ 368 | BoxData[ 369 | RowBox[ 370 | { 371 | "LibraryFunctionError", 372 | "[", 373 | RowBox[{"\"LIBRARY_TYPE_ERROR\"", ",", "1"}], 374 | "]" 375 | } 376 | ] 377 | ], 378 | "Output", 379 | CellLabel -> "Out[10]=" 380 | ] 381 | }, 382 | Open 383 | ] 384 | ], 385 | Cell[ 386 | BoxData[RowBox[{"LibraryUnload", "[", "lib", "]"}]], 387 | "Input", 388 | CellLabel -> "In[11]:=" 389 | ] 390 | }, 391 | Open 392 | ] 393 | ] 394 | }, 395 | Open 396 | ] 397 | ] 398 | }, 399 | StyleDefinitions -> "Default.nb" 400 | ] --------------------------------------------------------------------------------