Rustmex

A library providing convenient Rust bindings to Matlab's MEX C api.

Rustmex makes writing MEX functions in Rust a bit easier. It convert Matlab types, and the arguments it provides to mexFunction into more Rusty types, which can then be used to interface with other Rust code easily.

For installation and documtoentation & linkage examples, refer to the documentation.

v0.6 Update Notes

Rustmex v0.6 constitutes a major redesign of the crate. It has been broken up into a set of crates, such that each crate is compilable separately; feature flags are no longer required for Rustmex itself to compile. However, the easiest installation method is still to use feature flags to select the appropriate backend; confer to the documentation of the backend module for instructions. The 'normal' user facing API of Rustmex should however still mostly be the same as before; only the internals have changed.

Usage Examples

This section contains some examples of how Rustmex can be used. Note however that these are not tested, since testing MEX functions involve starting a Matlab/Octave interpreter, and so this cannot be done automatically. Future versions of Rustmex will come with runnable examples.

That being said, each MEX function file has an entrypoint called mexFunction. This is a C FFI function, which, preferably, you do not want to write yourself. Instead, rustmex provides the entrypoint macro; a macro to mark your Rust entrypoint with. For example: ```rust,ignore use rustmex::prelude::*;

[rustmex::entrypoint]

fn hello_world(lhs: Lhs, rhs: Rhs) -> rustmex::Result<()> { println!("Hello Matlab!"); Ok(()) } ```

Note that this example mirrors the definition of mexFunction itself: Matlab has already allocated a return value array, you just need to place your results into it.

The FromMatlabError is for when you want to convert an mxArray into a more Rusty data type. These conversions are not infallible: Matlab is dynamically typed, and the provided mxArray must have the same type and size as the type we want to convert it into.

As a more convoluted example: ```rust,ignore use rustmex::prelude::*;

[rustmex::entrypoint]

fn euclideanlength(lhs: Lhs, rhs: Rhs) -> rustmex::Result<()> { let v: &[f64] = rhs .get(0) .errorifmissing("euclideanlength:missinginput", "Missing input vector to compute the length of")? .dataslice()?;

// I recommend to only execute your planned computation once you're sure it
// actually needs to be computed — it's a bit of a waste to compute an expensive
// result without somewhere to return it to.
if let Some(ret) = lhs.get_mut(0) {
    ret.replace(v.iter().map(|x|x*x).sqrt().to_matlab());
}
Ok(())

} ```

This example computes the Euclidean length of an input vector. Note that type annotations are (almost always) needed for the return type of data_slice() and from_matlab().

Regarding [FromMatlab][convert::FromMatlab], this library also supports building NDarrays from mxArrays. It will ensure that NDarray understands the data the same way matlab does. For example, the following prints out a debug representation of the array: ```rust,ignore use rustmex::prelude::*; use ndarray::ArrayViewD;

[rustmex::entrypoint]

fn displaymatrix(lhs: Lhs, rhs: Rhs) -> rustmex::Result<()> { if let Some(mx) = rhs.get(0) { let mat = ArrayViewD::frommatlab(mx)?; eprintln!("{mat:#?}"); } Ok(()) } ```

Calling back into Matlab is also supported. For example, to compute the square root of the sum of squares (i.e. nd-pythagoras): matlab % Call Rust MEX file x = rusty_fn_call(@(x) sqrt(sum(x.^2)), 1:10) ```rust,ignore use rustmex::prelude::* use rustmex::function::Function;

[rustmex::entrypoint]

fn rustyfncall(lhslice: rustmex::Lhs, rhslice: rustmex::Rhs) -> rustmex::Result<()> {

let f = rhslice
    .get(0)
    .error_if_missing("rusthello:no_fn", "Didn't get a function")?
    .to_rust::<Function<_>>()?;

if let Some(r) = lhslice.get_mut(0) {
    // Just forward the remaining arguments
    let mut results: Box<[Option<MxArray>; 1]> = f.call(&rhslice[1..]).unwrap();

    let v = results[0].take().unwrap();

    r.replace(v);
};

return Ok(());

} prints: text x = 19.621 ```

If you assume something about the data you receive, but it might not yet be in the right shape, you might want to reshape. Rustmex enables ergonomically reshaping data: you can apply the ? operator on a Result with a ShapeError in functions which return a rustmex::Result: ```rust,ignore use rustmex::prelude::*; use ndarray::{ArrayViewD, Ix2};

[rustmex::entrypoint]

fn displaymatrix(lhs: Lhs, rhs: Rhs) -> rustmex::Result<()> { if let Some(mx) = rhs.get(0) { let mat = ArrayViewD::frommatlab(mx)? .intodimensionality()? .intoshape((1, 4))?; eprintln!("{mat:#?}"); } Ok(()) } ```

Licence

This is licensed to you under the Mozilla Public License, version 2. You can the licence in the LICENCE file in this project's source tree root folder.

Authors