Message Boards Message Boards

Wolfram + Rust: Announcing the wolfram-library-link Rust crate

Posted 2 years ago

GitHub repository: https://github.com/WolframResearch/wolfram-library-link-rs

This post is a short announcement of the wolfram-library-link Rust crate, intended to get the word out to interested early adopters.

What is Rust?

The Rust programming language is a modern, performant, and productive programming language. Rust's mission statement is to be:

A language empowering everyone to build reliable and efficient software.

Rust enables the developer to write performant low-level code with performance on par with the C/C++ family of languages, but provides the ergonomic benefits and safety guarantees typical of a higher level programming language.

Rust provides a productive balance between performance and reliability for authors wishing to extend their Wolfram Language projects with optimized native code, connections to external libraries or services, without the worry of introducing low-level problems like memory or thread safety bugs into their code.

wolfram-library-link

wolfram-library-link is a Rust library providing efficient, ergonomic access to the Wolfram LibraryLink interface for Rust programs.

A simple Rust program written using wolfram-library-link looks like:

use wolfram_library_link::export;

/// Return the square of an integer.
#[export]
fn square(x: i64) -> i64 {
    x * x
}

Once compiled, the square() function can be loaded into the Wolfram Language using:

square = LibraryFunctionLoad["<library path>", "square", {Integer}, Integer]

and can then be called like any other function:

square[5]    (* Returns 25 *)

Want to get hands-on right away? Check out the Quick Start tutorial to begin writing your first Rust LibraryLink project.

Compound numeric data

In addition to scalar arguments, wolfram-library-link supports passing compound numeric data, via the the NumericArray data type.

Use the NumericArray type to efficiently pass data between Rust and the Wolfram Language, and query and manipulate the data in a type-safe way from within Rust:

fn total_list(list: &NumericArray<i64>) -> i64 {
    // Functional one-liner that folds over the list elements to sum them.
    list.as_slice().into_iter().sum()
}

which can be loaded and called using:

totalList = LibraryFunctionLoad[
    "<library path>",
    "total_list",
    {{LibraryDataType[NumericArray, "Integer64"], "Constant"}},
    Integer
];

totalList[NumericArray[{1, 2, 3}, "Integer64"]]    (* Returns 6 *)

Passing arbitrary expressions using WSTP

In addition to passing native data types, LibraryLink also supports passing arbitrary expressions between compiled library functions and the Wolfram Language, using WSTP.

wolfram-library-link provides access to WSTP via the wstp crate's Link type. A WSTP LibraryLink function is defined using the #[export(wstp)] macro, as shown in the following example:

use wolfram_library_link::{export, expr::{Expr, Symbol}, wstp::Link};

/// This function returns the current number of seconds passed since the Unix epoch time
/// as a Quantity[_, "Seconds"] expression.
#[export(wstp)]
fn time_since_epoch(link: &mut Link) {
    use std::time::{SystemTime, UNIX_EPOCH};

    let arg_count = link.test_head("List").unwrap();
    assert!(arg_count == 0, "expected zero arguments, got {arg_count}");

    let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();

    // Write the return expression: Quantity[<duration>, "Seconds"]
    link.put_expr(&Expr::normal(Symbol::new("System`Quantity"), vec![
        Expr::real(duration.as_secs_f64()),
        Expr::string("Seconds"),
    ]))
    .unwrap();
}

WSTP LibraryLink functions are loaded using LinkObject as the parameter and return type:

timeSinceEpoch = LibraryFunctionLoad[
    "<library path>",
    "time_since_epoch",
    LinkObject,
    LinkObject
];

timeSinceEpoch[]    (* Returns a Quantity[_Real, "Seconds"] value *)

But wait, there's more!

These short examples serve to illustrate that LibraryLink for Rust programs are concise, expressive, and easy to write. But there's much more that isn't covered in these examples, including:

wolfram-library-link is full of useful features for authors interested in writing efficient, expressive, and robust Wolfram libraries. Future posts will discuss these features in more detail.

Resources

  • Quick Start: The LibraryLink for Rust Quick Start is a complete tutorial covering how to create a new Rust library, compile it, and call into it from the Wolfram Language.

  • Example Programs The wolfram-library-link repository contains additional examples demonstrating the main features of the wolfram-library-link API.

  • API Documentation: Complete documentation of the wolfram-library-link API available from docs.rs.

  • Why Rust?: This document provides a high-level overview of why the Rust programming language might be useful to Wolfram Language developers interested in writing efficient native code or connecting to external libraries — especially for those who've been hesitant to use C or C++ to do the same.

Appendix: wstp and wolfram-app-discovery

This post is primarily an announcement of the wolfram-library-link crate. However, the new wstp and wolfram-app-discovery crates also merit their own brief mention.

Like wolfram-library-link, the wstp crate is a set of Rust bindings to an existing Wolfram C interface; in this case, the Wolfram Symbolic Transfer Protocol (WSTP). WSTP is a protocol enabling efficient transfer of Wolfram Language expressions between programs.

The functionality of wolfram-app-discovery is new. This crate provides automated, programatic discovery of Wolfram Language installations on a given computer. wolfram-app-discovery is intended to empower the creation of programs that depend on the Wolfram Language, but whose entry point is not the Wolfram Language or the notebook interface.

In a similar manner to how many Java programs expect to locate a Java Runtime on the users system, wolfram-app-discovery can be used to write programs that are portable between different computers that have the Wolfram Language "runtime" installed.

Example: md2nb

md2nb is a program for converting Markdown files into Wolfram Notebooks.

md2nb leverages the Markdown functionality available in the Rust ecosystem to parse and process a Markdown file, and uses wstp and wolfram-app-discovery to communicate with a local Wolfram Language installation to programmatically generate the notebook.

Interested in what md2nb can do? Check out the "WolframCommunityAnnouncement (brief).nb" file that is attached to this post to see what this post looks like rendered as a notebook!

Attachments:
POSTED BY: Connor Gray
2 Replies

enter image description here -- you have earned Featured Contributor Badge enter image description here Your exceptional post has been selected for our editorial column Staff Picks http://wolfr.am/StaffPicks and Your Profile is now distinguished by a Featured Contributor Badge and is displayed on the Featured Contributor Board. Thank you!

POSTED BY: EDITORIAL BOARD
Posted 8 months ago

This is great, Conner. I am using this capability to speed up a very lengthy document ingestion process. Question: do you anticipate adding the ability to return string lists from RUST functions under WSTP?

POSTED BY: David Ostby
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract