A Rust template for building dynamically-loaded Mercury Network Abstraction
(NA) plugins. Produces a libna_plugin_abc.so that Mercury discovers at
runtime via NA_PLUGIN_PATH, identical in interface to a C plugin but with
the implementation written in Rust.
| Tool | Version | Purpose |
|---|---|---|
| Rust (rustc, cargo) | stable >= 1.77 | Compile the plugin (c"" literals require 1.77+) |
| libclang-dev | >= 13 | Required by the bindgen crate to parse C headers |
| CMake | >= 3.15 | Build wrapper and C test suite |
| Mercury | >= 2.4 | Provides libna.so, headers, and cmake config |
Cargo automatically fetches the bindgen and pkg-config build-dependencies.
Cargo.toml # cdylib crate config
build.rs # Runs bindgen, emits link flags
wrapper.h # Thin #include <na_plugin.h> for bindgen
src/
lib.rs # Exports na_abc_class_ops_g ops table
plugin.rs # All ~34 extern "C" callback stubs
CMakeLists.txt # Finds Mercury, invokes cargo, builds C tests
test/ # C test suite (language-agnostic, from Mercury)
rename-plugin.sh # Rename "abc" to your plugin name
If Mercury is installed and discoverable via pkg-config:
PKG_CONFIG_PATH=/path/to/mercury/lib/pkgconfig cargo build --releaseThe plugin is at target/release/libna_plugin_abc.so.
If Mercury is not in pkg-config, set the paths explicitly:
MERCURY_INCLUDE_DIR=/path/to/mercury/include \
MERCURY_LIB_DIR=/path/to/mercury/lib \
cargo build --releaseMultiple include directories can be colon-separated:
MERCURY_INCLUDE_DIR=/path/to/include:/path/to/extra/headers ...mkdir build && cd build
cmake .. -Dmercury_DIR=/path/to/mercury/share/cmake/mercury
make -j$(nproc)This builds both the Rust plugin (via cargo) and the C test executables.
The plugin .so is placed in build/cargo-build/release/.
From the CMake build directory:
LD_LIBRARY_PATH=/path/to/mercury/lib ctest --output-on-failureThe test suite exercises the plugin through Mercury's public NA API. Since
the template stubs return NA_PROTOCOL_ERROR from initialize(), only the
abc_proc test (which does not require initialization) will pass. The
remaining tests will pass once you implement the callbacks.
| Test | Result | Reason |
|---|---|---|
abc_proc |
Pass | Standalone serialization test, no plugin init needed |
abc_init |
Fail | initialize() returns NA_PROTOCOL_ERROR |
abc_msg |
Fail | Cannot initialize plugin |
abc_lookup |
Fail | Cannot initialize plugin |
abc_rpc |
Fail | Cannot initialize plugin |
abc_bulk |
Fail | Cannot initialize plugin |
To rename from "abc" to your own plugin name (e.g. "xyz"):
./rename-plugin.sh xyzThis updates Cargo.toml, CMakeLists.txt, src/lib.rs, src/plugin.rs,
and all test files. The output library becomes libna_plugin_xyz.so with
exported symbol na_xyz_class_ops_g.
Remove any old build/ and target/ directories before rebuilding.
-
Rename:
./rename-plugin.sh <name> -
Define state structs in
src/plugin.rsfor your addresses, memory handles, operation IDs, and class-level state. -
Implement callbacks in
src/plugin.rs. Each function has a doc-comment explaining the expected behaviour and a// TODOmarker. Key FFI patterns:-
Storing Rust state in C structs: Use
Box::into_raw()to store a boxed struct inna_class.plugin_classduringinitialize, andBox::from_raw()to reclaim it duringfinalize. -
Completing async operations: Fill in an
na_cb_completion_datastruct and callna_cb_completion_add(context, &mut completion_data). -
Nullable function pointers:
Some(f)= non-NULL callback,None= NULL (optional callback). Set unused optional callbacks toNonein the ops table inlib.rs.
-
-
Run tests:
cd build && cmake .. && make && ctest
Point Mercury at your plugin directory:
NA_PLUGIN_PATH=/path/to/dir/containing/libna_plugin_xyz.so your_application