Safe, efficient, and ergonomic bindings to Wolfram LibraryLink and the Wolfram Language

Overview

wolfram-library-link

Bindings to the Wolfram LibraryLink interface, making it possible to call Rust code from the Wolfram Language.

This library is used for writing Rust programs that can be loaded by the Wolfram LibraryLink family of functions, specifically by LibraryFunctionLoad[].

Features

  • Efficiently call Rust functions from Wolfram code.
  • Pass arbitrary Wolfram expressions to and from Rust code.
  • Evaluate Wolfram expressions from Rust code.
  • Respond to Wolfram abort requests while in Rust code.
  • Safe API for the Wolfram Symbolic Transport Protocol, using the wstp crate.

Follow the Quick Start guide to begin using wolfram-library-link.

See Why Rust? for an overview of some of the advantages Rust has when writing native code for use from the Wolfram Language: performance, memory and thread safety, high-level features, and more.

Quick Examples

The examples in this section are written with two back-to-back code blocks. The first shows the Rust code, and the second shows the Wolfram Language code needed to load and use the related Rust function(s).

Basic data types

use wolfram_library_link::export;

export![square(_)];

fn square(x: i64) -> i64 {
    x * x
}
square = LibraryFunctionLoad["...", "square", {Integer}, Integer];

square[5]

See also: LibraryFunctionLoad

Efficient numeric arrays

Create an array of a million integers in Wolfram Language and compute the total using Rust:

use wolfram_library_link::{export, NumericArray};

export![total(_)];

fn total(array: &NumericArray<i64>) -> i64 {
    array.as_slice().into_iter().sum()
}
total = LibraryFunctionLoad[
    "...",
    "square",
    {LibraryDataType[NumericArray, "Integer64"]},
    Integer
];

total[NumericArray[Range[1000000], "Integer64"]]

See also: NumericArray, LibraryDataType

Example Programs

The wolfram-library-link/examples subdirectory contains sample programs demonstrating features of the wolfram-library-link API.

Rust code Wolfram Language code Demonstrates ...
basic_types.rs BasicTypes.wlt how to write Rust LibraryLink functions utilizing the basic, native types that can be passed efficiently, like integers, floating-point real numbers, and strings.
numeric_arrays.rs NumericArrays.wlt how the NumericArray data type can be used to efficiently pass large multi-dimensional arrays of uniform numeric data.
wstp.rs WSTP.wlt how WSTP [[Link]]s can be used to pass arbitrary expressions to and from LibraryLink functions.
aborts.rs Aborts.wlt how Rust code can respond to Wolfram abort requests.
async_file_watcher.rs AsyncExamples.wlt how Rust code can generate asynchronous events that trigger Wolfram evaluations to process the event.
managed.rs ManagedExpressions.wlt how the managed expression API can be used to free library data when a Wolfram expression is deallocated.
data_store.rs DataStore.wlt how the DataStore data type can be used to efficiently pass arbitrary expression-like heterogenous structures made up of native LibraryLink data types.

Raw functions

These examples demonstrate how to write functions that use the "raw" low-level LibraryLink and WSTP interfaces, using the extern "C" ABI, the low-level MArgument and WSLINK types, and manual WSTP operations.

Rust code Wolfram Language code
raw_librarylink_function.rs and raw_wstp_function.rs RawFunctions.wlt

Additional examples

In addition to the polished high-level examples, the wolfram-library-link/examples/tests/ directory contains test code for a more exhaustive range of functionality and behavior, and may be a useful additional reference. The RustLink/Tests/ directory contains the Wolfram Language unit testing logic that loads and calls the test functions.

Building wolfram-library-link

wolfram-library-link depends on the wstp crate for bindings to the Wolfram Symbolic Transport Protocol (WSTP). Building the wstp crate requires access to the WSTP SDK, which provides the WSTP static library. wstp uses wolfram-app-discovery to locate a local installation of the Wolfram Language that contains a suitable copy of the WSTP SDK. If the WSTP SDK cannot be located, wstp will fail to build, and consequently, so will wolfram-library-link.

If you have installed the Wolfram Language to a location unknown to wolfram-app-discovery, you may specify the installed location manually by setting the WOLFRAM_APP_DIRECTORY environment variable. See Configuring wolfram-app-discovery for details.

Related Links

Related crates

  • wstp — bindings to the Wolfram Symbolic Transport Protocol, used for passing arbitrary Wolfram expressions between programs.
  • wolfram-expr — native Rust representation of Wolfram Language expressions.
  • wolfram-app-discovery — utility for locating local installations of Wolfram applications and the Wolfram Language.

Related documentation

Developer Notes

See Development.md for instructions on how to perform common development tasks when contributing to the wolfram-library-link crate.

See Maintenance.md for instructions on how to keep wolfram-library-link up to date as new versions of the Wolfram Language are released.

License

Licensed under either of

at your option.

Note: Licensing of the WSTP library linked by the wstp crate is covered by the terms of the MathLink License Agreement.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

See CONTRIBUTING.md for more information.

Comments
  • Failure in running basic_expressions example

    Failure in running basic_expressions example

    basic_expressions compiles successfully but in Mathematica, as shown in the image, the first arguments get Echoed and then it returns failure. Subsequent calls return the string without any Echoing.

    image

    Did I miss something ?

    bug documentation 
    opened by ben-izd 5
  • Failed to compile on windows

    Failed to compile on windows

       Compiling wstp-sys v0.2.1
       Compiling wolfram-library-link-sys v0.2.1
       Compiling wstp v0.2.1
       Compiling wolfram-library-link v0.2.1
    error[E0308]: mismatched types
       --> C:\Users\Administrator\.cargo\registry\src\github.com-1ecc6299db9ec823\wolfram-library-link-0.2.1\src\numeric_array.rs:175:12
        |
    175 |     Cast = MNumericArray_Convert_Cast,
        |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
    
    error[E0308]: mismatched types
       --> C:\Users\Administrator\.cargo\registry\src\github.com-1ecc6299db9ec823\wolfram-library-link-0.2.1\src\numeric_array.rs:176:13
        |
    176 |     Check = MNumericArray_Convert_Check,
        |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
    
    error[E0308]: mismatched types
       --> C:\Users\Administrator\.cargo\registry\src\github.com-1ecc6299db9ec823\wolfram-library-link-0.2.1\src\numeric_array.rs:177:14
        |
    177 |     Coerce = MNumericArray_Convert_Coerce,
        |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
    
    error[E0308]: mismatched types
       --> C:\Users\Administrator\.cargo\registry\src\github.com-1ecc6299db9ec823\wolfram-library-link-0.2.1\src\numeric_array.rs:178:13
        |
    178 |     Round = MNumericArray_Convert_Round,
        |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
    
    error[E0308]: mismatched types
       --> C:\Users\Administrator\.cargo\registry\src\github.com-1ecc6299db9ec823\wolfram-library-link-0.2.1\src\numeric_array.rs:179:13
        |
    179 |     Scale = MNumericArray_Convert_Scale,
        |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
    
    error[E0308]: mismatched types
       --> C:\Users\Administrator\.cargo\registry\src\github.com-1ecc6299db9ec823\wolfram-library-link-0.2.1\src\numeric_array.rs:180:19
        |
    180 |     ClipAndCast = MNumericArray_Convert_Clip_Cast,
        |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
    
    error[E0308]: mismatched types
       --> C:\Users\Administrator\.cargo\registry\src\github.com-1ecc6299db9ec823\wolfram-library-link-0.2.1\src\numeric_array.rs:181:20
        |
    181 |     ClipAndCheck = MNumericArray_Convert_Clip_Check,
        |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
    
    error[E0308]: mismatched types
       --> C:\Users\Administrator\.cargo\registry\src\github.com-1ecc6299db9ec823\wolfram-library-link-0.2.1\src\numeric_array.rs:182:21
        |
    182 |     ClipAndCoerce = MNumericArray_Convert_Clip_Coerce,
        |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
    
    error[E0308]: mismatched types
       --> C:\Users\Administrator\.cargo\registry\src\github.com-1ecc6299db9ec823\wolfram-library-link-0.2.1\src\numeric_array.rs:183:20
        |
    183 |     ClipAndRound = MNumericArray_Convert_Clip_Round,
        |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
    
    error[E0308]: mismatched types
       --> C:\Users\Administrator\.cargo\registry\src\github.com-1ecc6299db9ec823\wolfram-library-link-0.2.1\src\numeric_array.rs:184:20
        |
    184 |     ClipAndScale = MNumericArray_Convert_Clip_Scale,
        |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
    
    For more information about this error, try `rustc --explain E0308`.
    error: could not compile `wolfram-library-link` due to 10 previous errors
    
    bug 
    opened by oovm 5
  • DLL Locked by Mathematica

    DLL Locked by Mathematica

    Have searched around for an answer but haven't found anything useful, here is my problem: While iterating between Mathematica and the IDE (VS Code in this case) I couldn't go past the first build as Mathematica locks the DLL library so the build fails with this error:

    fatal error LNK1104: cannot open file 'C:\...\target\debug\deps\hello_cargo.dll'
    

    Anyone knows of a workaround other than quitting completely out of Mathematica? And apologies if this is not the right place..

    opened by netlander 2
  • feature: `#[init]` macro to automatically define a safe library initialization function

    feature: `#[init]` macro to automatically define a safe library initialization function

    The new #[init] macro is an alternative to manually defining a WolframLibrary_initialize() function.

    Before:

    #[no_mangle]
    pub unsafe extern "C" fn WolframLibrary_initialize(data: sys::WolframLibraryData) -> c_int {
        match wll::initialize() {
            Ok(()) => 0,
            Err(()) => 1,
        }
    
        // Initialization tasks. Careful not to `panic!()`!
    }
    

    After:

    #[wll::init]
    fn init() {
        // Initialization tasks. Okay to `panic!()`.
    }
    
    opened by ConnorGray 2
  • feature: Wrap the LibraryLink managed expressions C API

    feature: Wrap the LibraryLink managed expressions C API

    This commit adds bindings, examples, and basic tests for the LibraryLink managed expression API.

    @okofish FYI. Happy to hear any feedback you have on using this API, or have any suggestions on documentation or ergonomics.

    opened by ConnorGray 2
  • bugfix: Clear WSTP link when panic occurs after partial put

    bugfix: Clear WSTP link when panic occurs after partial put

    Normally, the wrapper function that is automatically generated by the #[export(wstp)] macro will catch Rust panics and translate them into a Wolfram Failure["RustPanic", ..] expression that is written to the WSTP Link as the return value of the function.

    However, if the Link already contains partially written data, the catch-panic-and-write-to-link logic was not fully resetting the link to clear that partially written data before writing the Failure[..] result.

    When this happened, instead of the function returning either the partial expression (which would not be meaningful) or the panic Failure[..], the Wolfram Kernel would appropriately detect that the link contained uninterpretable partial data, and yield instead the expression (LibraryFunctionError["LIBRARY_FUNCTION_ERROR", 6]) representing the error code returned by the function, which is not helpful at determining the cause of the panic.

    With this change, partial data written to the link will be cleared before the Failure[..] expression is written, so that a complete expression is available to be read from the link upon returning to the Wolfram Kernel.

    The following example illustrates a situation where this bug occurred:

    #[export(wstp)]
    fn do_something(link: &mut Link) {
        link.put_function("List", 3).unwrap(); // Start writing a list of three elements
        todo!(); // Panic with an incomplete List[... expression left on the link
    }
    
    opened by ConnorGray 0
  • bugfix(#29): Fix Windows compilation error due to signedness of constants

    bugfix(#29): Fix Windows compilation error due to signedness of constants

    This is a fix for #29.

    The existing code assumed that the Wolfram LibraryLink constants would have the same size and signedness on all platforms. This assumption was not correct on Windows targeting MSVC, where constants that would be u32 on other platforms would be i32.

    See also:

    • https://github.com/rust-lang/rust-bindgen/issues/1244
    • https://github.com/rust-lang/rust-bindgen/issues/1361
    opened by ConnorGray 0
  • docs: Rename 'Call back into Wolfram from Rust' to 'Evaluate Wolfram code from Rust'

    docs: Rename 'Call back into Wolfram from Rust' to 'Evaluate Wolfram code from Rust'

    I changed my mind after making #38. The phrase 'call back' is a bit too technical and less likely to be familiar than simply 'evaluate', which is a clearer statement of what's happening.

    Additionally, a 'callback function' (i.e. a function pointer / closure) is one mechanism for executing code across a library / language boundary, but that is not at all the mechanism used for Rust -> Wolfram evaluations. The new name avoids this potentially misleading connotation.

    opened by ConnorGray 0
  • bugfix: Fix docs.rs build failure due to case-sensitive file name mismatch

    bugfix: Fix docs.rs build failure due to case-sensitive file name mismatch

    The file is called ManualWSTP.wlt, but the include_str!(..) call used "ManualWstp.wlt".

    This worked on macOS (where I develop) because macOS is case-insensitive. This failed on docs.rs because docs.rs uses Linux build environments, and Linux is case-sensitive.

    opened by ConnorGray 0
Owner
Wolfram Research, Inc.
Wolfram Research, Inc.
Representing Wolfram Language expressions in Rust.

wolfram-expr Representation of Wolfram Language expressions. Examples Construct the expression {1, 2, 3}: use wolfram_expr::{Expr, Symbol}; let expr

Wolfram Research, Inc. 7 Aug 18, 2022
Safe, idiomatic bindings to cFE and OSAL APIs for Rust

n2o4 The n2o4 crate provides safe, idiomatic Rust bindings to the APIs of cFE and OSAL, the libraries of the Core Flight System (cFS). IMPORTANT NOTE

null 3 Aug 29, 2022
Safe Rust bindings to the DynamoRIO dynamic binary instrumentation framework.

Introduction The dynamorio-rs crate provides safe Rust bindings to the DynamoRIO dynamic binary instrumentation framework, essentially allowing you to

S.J.R. van Schaik 17 Nov 21, 2022
A type-safe, high speed programming language for scalable systems

A type-safe, high speed programming language for scalable systems! (featuring a cheesy logo!) note: the compiler is unfinished and probably buggy. if

Hail 0 Sep 14, 2022
🍋: A General Lock following paper "Optimistic Lock Coupling: A Scalable and Efficient General-Purpose Synchronization Method"

Optimistic Lock Coupling from paper "Optimistic Lock Coupling: A Scalable and Efficient General-Purpose Synchronization Method" In actual projects, th

LemonHX 22 Oct 13, 2022
Proof-of-concept for a memory-efficient data structure for zooming billion-event traces

Proof-of-concept for a gigabyte-scale trace viewer This repo includes: A memory-efficient representation for event traces An unusually simple and memo

Tristan Hume 59 Sep 5, 2022
A HashMap/Vector hybrid: efficient, ordered key-value data storage in Rust.

hashvec A HashVec is a hash map / dictionary whose key-value pairs are stored (and can be iterated over) in a fixed order, by default the order in whi

Skye Terran 2 May 16, 2022
An efficient runtime for asynchronous applications in Rust.

PhotonIO PhotonIO is an efficient runtime for asynchronous applications in Rust. Features Asynchronous filesystem and networking I/O for Linux based o

PhotonDB 40 Jan 4, 2023
A pure-rust(with zero dependencies) fenwick tree, for the efficient computation of dynamic prefix sums.

indexset A pure-rust(with zero dependencies, no-std) fenwick tree, for the efficient computation of dynamic prefix sums. Background Did you ever have

Bruno Rucy Carneiro Alves de Lima 2 Jul 13, 2023
The Fast Vector Similarity Library is designed to provide efficient computation of various similarity measures between vectors.

Fast Vector Similarity Library Introduction The Fast Vector Similarity Library is designed to provide efficient computation of various similarity meas

Jeff Emanuel 243 Sep 6, 2023
Build database expression type checker and vectorized runtime executor in type-safe Rust

Typed Type Exercise in Rust Build database expression type checker and vectorized runtime executor in type-safe Rust. This project is highly inspired

Andy Lok 89 Dec 27, 2022
Simple, safe way to store and distribute tensors

safetensors Safetensors This repository implements a new simple format for storing tensors safely (as opposed to pickle) and that is still fast (zero-

Hugging Face 402 Dec 29, 2022
Thread-safe clone-on-write container for fast concurrent writing and reading.

sync_cow Thread-safe clone-on-write container for fast concurrent writing and reading. SyncCow is a container for concurrent writing and reading of da

null 40 Jan 16, 2023
Safe, comp time generated queries in rust

query_builder For each struct field following methods will be generated. All fields where_FIELDNAME_eq Numeric fields where_FIELDNAME_le where_FIELDNA

Amirreza Askarpour 2 Oct 31, 2021
Safe MMDeploy Rust wrapper.

Introduction Safe MMDeploy Rust wrapper. News (2022.9.29) This repo has been added into the OpenMMLab ecosystem. (2022.9.27) This repo has been added

Mengyang Liu 14 Dec 15, 2022
A additional Rust compiler pass to detect memory safe bugs of Rust programs.

SafeDrop A additional Rust compiler pass to detect memory safe bugs of Rust programs. SafeDrop performs path-sensitive and field-sensitive inter-proce

Artisan-Lab  (Fn*) 5 Nov 25, 2022
Linked Atomic Random Insert Vector: a thread-safe, self-memory-managed vector with no guaranteed sequential insert.

Linked Atomic Random Insert Vector Lariv is a thread-safe, self-memory-managed vector with no guaranteed sequential insert. It internally uses a linke

Guillem Jara 8 Feb 1, 2023
Blazing fast, memory safe & modern Linux package manager written in Rust.

paket Blazing fast, memory safe & modern Linux package manager written in Rust. Roadmap Version: 0.1 Paket.toml file parsing. (#1, #2) CLI handling (p

null 4 Oct 19, 2023
A repository for showcasing my knowledge of the Rust programming language, and continuing to learn the language.

Learning Rust I started learning the Rust programming language before using GitHub, but increased its usage afterwards. I have found it to be a fast a

Sean P. Myrick V19.1.7.2 2 Nov 8, 2022