Rust Module: rustModuleTemplate
Executive Summary
This basic Rust Basilisk module can be copied as a starting point for a new
Rust module. It demonstrates both an individual message connection and a
fixed-size array of two message connections. The module reads optional input
messages, increments each first data-vector element, and writes the results to
the corresponding outputs. Its implementation is in rustModuleTemplate.rs
beside this documentation file, following the normal Basilisk module naming
convention.
Message Connection Descriptions
The following diagram and table list the module input and output messages.
Msg Variable Name |
Msg Type |
Description |
|---|---|---|
dataInMsg |
(optional) Input data vector. A zero vector is used when this message is not connected. |
|
dataInMsgs |
(optional, two-element array) Input data vectors. A zero vector is used for each element that is not connected. |
|
dataOutMsg |
Input data vector with its first element incremented by the module state. |
|
dataOutMsgs |
(two-element array) Input data vectors with each first element incremented by the module state. |
Module Assumptions and Limitations
This module is a template only and does not model a physical system. It
demonstrates the Rust module lifecycle, explicit message-port annotations,
named input and output values, optional message inputs, output messages, and
fixed-size arrays of message ports. It also demonstrates a Python-configurable
increment parameter that is initialized in Rust, validated immediately by
its generated setter, and checked again during reset. The nested
sampleParameters value and two-dimensional sampleMatrix array exercise
composite configuration types through the generated Rust, C++, SWIG, and
Python interfaces. The legacyDummy parameter demonstrates generated
Basilisk deprecation warnings. The
panicOnUpdate field is a test-only fault-injection hook used to verify that
the generated ABI contains an unexpected Rust panic before it crosses into
C++. The private module state also calls the safe
bsk_utilities::attitude::wrap_to_pi wrapper, illustrating access to
Basilisk’s existing C utility implementation without exposing raw pointers.
User Guide
Enable Rust module support when configuring Basilisk as described in [BETA] Making Rust Modules. Import and add the module to a task like any other compiled Basilisk module:
from Basilisk.architecture import messaging
from Basilisk.moduleTemplates import rustModuleTemplate
module = rustModuleTemplate.rustModuleTemplate()
simulation.AddModelToTask("taskName", module)
module.increment defaults to 1 and must be finite and strictly positive.
Assigning an invalid value raises BasiliskError immediately and preserves
the previous value. module.getIncrement() and
module.setIncrement(value) use the same generated Rust getter and setter
as the module.increment property. Reset repeats the validation as a
defensive check for defaults or changes made inside Rust.
The template also exposes grouped parameters and a fixed-size matrix. Nested configuration getters return a copy, so modify the copy and assign the whole value back to the module. Multidimensional Rust arrays appear as nested Python lists:
parameters = module.sampleParameters
parameters.gain = 2.5 # [-]
parameters.offset = -0.25 # [-]
module.sampleParameters = parameters
module.sampleMatrix = [[1.0, 2.0, 3.0], # [-]
[4.0, 5.0, 6.0]]
Both setters reject non-finite components, and the array setter also rejects a value with anything other than six total elements. A failed setter preserves the preceding configuration value.
The unused legacyDummy sample parameter is deprecated in favor of
dummy. Reading or writing it demonstrates the standard dated Basilisk
deprecation warning generated from the field annotation. New modules only
need such an annotation when retaining an old property during a migration.
Leave module.panicOnUpdate set to its default value of False during
normal use. Setting it to True deliberately panics during update so the
unit tests can verify panic containment and the rejection of later lifecycle
calls on the poisoned instance. Rust still destroys the instance normally.
The panic is reported once as BasiliskError without an additional default
Rust panic-hook report.
Operational modules should return BskError for expected failures rather
than adding a similar test hook.
The template’s Rust implementation shows how one individual output and a fixed-size output array are published together:
Ok(RustModuleTemplateOutputs {
dataOutMsg: Some(data_out_msg),
dataOutMsgs: data_out_msgs.map(Some),
})
The generated lifecycle writes each Some(payload) to its corresponding
port. Here it writes data_out_msg to dataOutMsg and both elements of
data_out_msgs to the matching elements of dataOutMsgs. Returning
None for an individual field or array element skips that output for the
current call. Basilisk automatically stamps each published message with this
module’s moduleID and current simulation time and sets its isWritten
flag. The template returns the default all-None output value from reset,
so it begins publishing only when update runs.
Connect module.dataInMsg when input data is available. When it is unconnected,
the module starts from a zero vector.
The dataInMsgs and dataOutMsgs fields demonstrate fixed-size arrays of
message ports. Python exposes each as a two-element list of normal Basilisk
message interfaces:
input_messages = [
messaging.CModuleTemplateMsg().write(first_payload),
messaging.CModuleTemplateMsg().write(second_payload),
]
for input_port, input_message in zip(module.dataInMsgs, input_messages):
input_port.subscribeTo(input_message)
output_recorders = [
output_port.recorder() for output_port in module.dataOutMsgs
]
for recorder in output_recorders:
simulation.AddModelToTask("taskName", recorder)
Each element is a live port. The array length is fixed by the Rust declaration, and the property cannot be assigned. Changing the entries or length of the returned Python list does not change the module’s fixed set of ports. See [BETA] Making Rust Modules for required arrays, optional arrays, lifecycle value types, and the current fixed-size-only limitation.
Generated Module API
This C-compatible interface is generated from the Rust module source.
-
struct RustModuleTemplateParameters
- #include <rustModuleTemplate.h>
Nested Python-visible parameters used to demonstrate grouped configuration.
-
struct RustModuleTemplateConfig
- #include <rustModuleTemplate.h>
Rust module configuration and message ports.
Public Members
-
double dummy
[-] Python-visible sample counter
-
double increment
[-] Positive amount added to the sample counter on each update
-
struct RustModuleTemplateParameters sampleParameters
[-] Nested, by-value sample configuration
-
double sampleMatrix[2][3]
[-] Two-dimensional sample configuration array
-
CModuleTemplateMsg_C dataInMsg
[-] Optional input message
-
CModuleTemplateMsg_C dataInMsgs[2]
[-] Fixed-size array of optional input messages
-
CModuleTemplateMsg_C dataOutMsg
[-] Individual output written from the returned
dataOutMsgvalue
-
CModuleTemplateMsg_C dataOutMsgs[2]
[-] Output array written element-by-element from returned
dataOutMsgs
-
double legacyDummy
[-] Deprecated sample parameter retained to demonstrate migration warnings
-
bool panicOnUpdate
[-] Test-only fault injection that deliberately panics during update
-
double dummy