repository
crates.io
API docs
issues
Install #
Install as a Cargo dependency.
cargo add mavspec --features specs
The specs
feature enables all core interfaces which are used by autogenerated code.
Since you probably want to generate code as a part of you build sequence, we suggest to also add MAVSpec as a build dependency.
cargo add --build mavspec --features generators
The generators
feature enables all code-generators.
Usage #
Each generator comes with two components that can be enabled by feature flags: specification, the core interfaces
required by autogenerated code, and the generator itself. For example, for Rust we provide rust
as a specification and
rust_gen
as a generator.
Rust #
API documentation for Rust code-generation can be found here.
Add MAVSpec with rust
feature to your dependencies.
cargo add mavspec --features rust
This feature enables interfaces upon which your generated code will depend. You can access these interfaces through
use mavspec::rust::spec
.
Optionally enable std
(for Rust standard library) or alloc
(for memory allocation support) features if your target
supports them (if you are not developing for an embedded devices, then we suggest to always enable std
).
Add MAVSpec with rust_gen
as a build dependency:
cargo add --build mavspec --features rust_gen
If necessary, add optional section to your Cargo.toml
to generate only specific messages:
[package.metadata.mavspec]
messages = ["HEARTBEAT", "PROTOCOL_VERSION", "MAV_INSPECT_V1", "COMMAND_INT", "COMMAND_LONG"]
all_enums = false
generate_tests = false
This will greatly reduce compile time and may slightly reduce memory footprint (if you are not going to expose autogenerated code as a part of your library API, then Rust compiler will probably optimize away all unused pieces).
The all_enum
key controls which enums will be generated. By default, only MAVLink enums required for selected messages
will be generated. Set all_enums = true
to generate all enums. If messages
key is not specified, then all_enums
won’t have any effect.
If you want to generate tests for generated code, set generate_tests
to true
. This mode is disabled by default.
Update your build.rs
:
use std::env::var;
use std::path::Path;
use mavspec::rust::BuildHelper;
fn main() {
// Assume that your library and `message_definitions` are both in the root of your project.
let sources = vec![
"./message_definitions/standard",
"./message_definitions/extra",
];
// Output path
let destination = Path::new(&var("OUT_DIR").unwrap()).join("mavlink");
// Path to your `Cargo.toml` manifest
let manifest_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("Cargo.toml");
// Parse XML definitions and generate Rust code
BuildHelper::builder(&destination)
.set_sources(&sources)
.set_manifest_path(&manifest_path)
.generate()
.unwrap();
}
The OUT_DIR
environment variable is provided by Rust build toolchain and points to output library for your crate. It
is considered a bad practice to write outside this path in the build scripts.
Finally, import generated code in your lib.rs
(or anywhere it seems appropriate):
mod mavlink {
include!(concat!(env!("OUT_DIR"), "/mavlink/mod.rs"));
}
pub use mavlink::dialects;
Check examples/rust
for a
slightly more elaborated example which uses Cargo features as flags for MAVLink dialect selection.
Rust naming conventions #
In MAVSpec
we are trying to keep balance between names as they appear in MAVLink XML definitions and Rust naming
conventions. In most situation we favor the Rust way unless it introduces confusions. In case we failed, and you are
confused, all entities are supplemented with descriptions where canonical MAVlink names are mentioned. Here is the list
of the naming rules:
- For structs and enums
MAVSpec
usesUpperCamelCase
. - For message fields we use
snake_case
. - For enum entries (enum entries) we use
UpperCamelCase
with MAVLink enum name prefix stripped (whenever applicable). For example, if bitmask enum has nameIMPORTANCE_LEVEL
and flag name isIMPORTANCE_LEVEL_THE_MATTER_OF_LIFE_AND_DEATH
, then flag name will beTheMatterOfLifeAndDeath
. - For bitmask flags (enum entries for enums which are bitmasks) we use
SCREAMING_SNAKE_CASE
with MAVLink enum name prefix stripped (whenever applicable). For example, if bitmask enum has nameVERY_IMPORTANT_FLAGS
and flag name isVERY_IMPORTANT_FLAGS_THE_MATTER_OF_LIFE_AND_DEATH_FLAG
, then flag name will beTHE_MATTER_OF_LIFE_AND_DEATH_FLAG
. - In the case of collision with rust keywords, we add underscore suffix. For example,
type
field ofHEARTBEAT
message will be encoded astype_
. - In the rare cases when symbolic name starts with numeric character, it will be prefixed with
_
.
Check mavspec_examples_rust.rs
which shows how the last two cases of inconvenient names are handled (this is not something of high aesthetic value but
in our defence we must say that all approaches we’ve considered looked equally ugly).