Marshalling Structs

When embedding Mun in other languages, you will probably want to retrieve, modify and send structures across the boundary - of the two languages. When this so-called marshalling occurs, there is often an associated performance penalty because the Mun Runtime needs to perform runtime checks to validate the provided data types.

Mun provides a homogeneous interface for marshalling any struct through a StructRef- a reference to a heap-allocated struct. The Mun Runtime automatically handles the conversion from a function return type into a StructRef and function arguments into Mun structs.

For structs with the gc memory kind, marshalling reuses the memory allocated by the garbage collector, but for structs with the value memory kind this requires their value to be copied into heap memory.

Listing 4-11 shows how to marshal Vector2 instances from Mun to Rust and vice versa, using the vector2_new and vector2_add functions - previously defined.

extern crate mun_runtime;
use mun_runtime::{Runtime, StructRef};
use std::env;

fn main() {
    let lib_path = env::args().nth(1).expect("Expected path to a Mun library.");

    // Safety: We assume that the library that is loaded is a valid munlib
    let builder = Runtime::builder(lib_path);
    let mut runtime = unsafe { builder.finish() }
        .expect("Failed to spawn Runtime");

    let a: StructRef = runtime.invoke("vector2_new", (-1.0f32, 1.0f32)).unwrap();
    let b: StructRef = runtime.invoke("vector2_new", (1.0f32, -1.0f32)).unwrap();
    let added: StructRef = runtime.invoke("vector2_add", (a, b)).unwrap();
}

Listing 4-11: Marshalling Vector2 instances

Accessing Fields

The API of StructRef consists of three generic methods for accessing fields: get, set, and replace; respectively for retrieving, modifying, and replacing a struct field. The desired field is specified using a string field_name parameter, which is identical to the one used with the dot notation in Mun code.

extern crate mun_runtime;
use mun_runtime::{Runtime, StructRef};
use std::env;

fn main() {
    let lib_path = env::args().nth(1).expect("Expected path to a Mun library.");

    // Safety: We assume that the library that is loaded is a valid munlib
    let builder = Runtime::builder(lib_path);
    let mut runtime = unsafe { builder.finish() }
        .expect("Failed to spawn Runtime");

    let mut xy: StructRef = runtime.invoke("vector2_new", (-1.0f32, 1.0f32)).unwrap();
    let x: f32 = xy.get("x").unwrap();
    xy.set("x", x * x).unwrap();
    let y = xy.replace("y", -1.0f32).unwrap();
}

Listing 4-12: Accessing fields of a StructRef