mavinspect/lib.rs
1//! **MAVInspect** is a library for parsing MAVLink
2//! [message definitions](https://github.com/mavlink/mavlink/tree/master/message_definitions/v1.0).
3//!
4//! <span style="font-size:24px">[πΊπ¦](https://mavka.gitlab.io/home/a_note_on_the_war_in_ukraine/)</span>
5//! [](https://gitlab.com/mavka/libs/mavinspect)
6//! [](https://crates.io/crates/mavinspect)
7//! [](https://docs.rs/mavinspect/latest/mavinspect/)
8//! [](https://gitlab.com/mavka/libs/mavinspect/-/issues/)
9//!
10//! # Usage
11//!
12//! Discover and parse MAVLink XML using [`Inspector`]:
13//!
14//! ```rust
15//! use mavinspect::parser::Inspector;
16//!
17//! // Instantiate inspector and load XML definitions from several locations
18//! let inspector = Inspector::builder()
19//! .set_sources(&[
20//! "./message_definitions/standard",
21//! "./message_definitions/extra",
22//! ])
23//! .set_include(&["crazy_flight"])
24//! .build()
25//! .unwrap();
26//!
27//! // Parse all XML definitions
28//! let protocol = inspector.parse().unwrap();
29//!
30//! // Get `CrazyFlight` custom dialect
31//! let crazy_flight = protocol.get_dialect_by_canonical_name("crazy_flight").unwrap();
32//!
33//! // Get `CRAZYFLIGHT_OUTCRY` message
34//! let outcry_message = crazy_flight.get_message_by_name("CRAZYFLIGHT_OUTCRY").unwrap();
35//! println!("\n`CRAZYFLIGHT_OUTCRY` message: {:#?}", outcry_message);
36//! ```
37//!
38//! Here we obtain an instance of [`Protocol`](protocol::Protocol) that contains a collection of
39//! dialects. Each [`Dialect`](protocol::Dialect) contains MAVLink [`enums`](protocol::Dialect::enums) and
40//! [`messages`](protocol::Dialect::messages) as well as additional information (like version or dialect dependencies).
41//!
42//! # Dialects Naming
43//!
44//! To avoid collision between similar dialect names like `SomeDialect` and `some_dialect` in libraries which use
45//! MAVInspect for code generation, we match dialect names up to `lower_snake_case`. This means that `SomeDialect`,
46//! `SOME_DIALECT`, and `some_dialect` will be considered the same, while `somedialect` will be considered as a
47//! different dialect. For example:
48//!
49//! ```rust
50//! # use mavinspect::parser::Inspector;
51//! let inspector_builder = Inspector::builder()
52//! // this is the original dialect name as it appears in the XML file name
53//! .set_include(&["SomeDialect"])
54//! // and this is a canonical name
55//! .set_include(&["some_dialect"]);
56//! // both rules will lead to the same result since names will be converted to `some_dialect` upon matching
57//! ```
58//!
59//! See details in [`Dialect::canonical_name`](protocol::Dialect::canonical_name).
60//!
61//! # Filtering
62//!
63//! The library provides two approaches to filter MAVLink definitions once they are loaded: the
64//! first is filtering entities within a dialect, the second is filtering out dialects itself.
65//!
66//! ## Filter Entities
67//!
68//! It is possible to filter [`Protocol`](protocol::Protocol) and a specific [`Dialect`](protocol::Dialect) by messages,
69//! enums, commands, and MAVLink [microservices](https://mavlink.io/en/services/). For example:
70//!
71//! ```rust
72//! # use mavinspect::parser::Inspector;
73//! # let inspector = Inspector::builder()
74//! # .set_sources(&["./message_definitions/standard"])
75//! # .set_include(&["common"])
76//! # .build().unwrap();
77//! # let protocol = inspector.parse().unwrap();
78//! use mavinspect::protocol::{Filter, Microservices};
79//!
80//! /* obtain protocol with `common` dialect */
81//!
82//! // Filter
83//! let filtered_protocol = protocol.filtered(
84//! &Filter::by_microservices(Microservices::HEARTBEAT | Microservices::MISSION)
85//! .with_messages(&["FILE_TRANSFER_PROTOCOL"])
86//! .with_enums(&["GIMBAL_DEVICE_CAP_FLAGS"])
87//! .with_commands(&["MAV_CMD_SET_*"])
88//! );
89//! ```
90//!
91//! Check [`Filter`](protocol::Filter) for details.
92//!
93//! ## Filter Dialects
94//!
95//! To filter dialects once they are loaded, use
96//! [`Protocol::with_dialects_included`](protocol::Protocol::with_dialects_included). This allows to
97//! filter out dialects based on their names, tags, and dependencies.
98//!
99//! # Metadata & Tags
100//!
101//! It is possible to add metadata to dialects by placing a `.dialects-metadata.yml` file
102//! into the directory with message definitions. For example:
103//!
104//! ```yaml
105//! # Tags that will be added to all dialects
106//! tags:
107//! - extra
108//! - test
109//! dialects:
110//! MyDialect:
111//! # Tags that will be added only to `MyDialect` dialect
112//! tags:
113//! - foo
114//! ```
115//!
116//! Tags may be used by downstream crates to distinguish dialects of a different kind. For example,
117//! [`mavlink-dialects`](https://crates.io/crates/mavlink-dialects) uses tags to filter user-defined
118//! dialects.
119//!
120//! Check [`MavInspectMetadata`](parser::MavInspectMetadata) for details.
121//!
122//! # Protocol Specification API
123//!
124//! MAVLink entities are defined in the [`protocol`] module. The root of the specification is
125//! [`Protocol`](protocol::Protocol) struct that contains a collection of [`Dialect`](protocol::Dialect). The latter
126//! contains dialect metadata, [`messages`](protocol::Dialect::messages) and [`enums`](protocol::Dialect::enums).
127//!
128//! Most of the entities with complex validation rules and lots of parameters are using
129//! [builder](https://rust-unofficial.github.io/patterns/patterns/creational/builder.html) instead of direct
130//! instantiation (no constructors). We assume that library clients prefer to use XML definitions as a ground truth for
131//! their dialects and are not very interested in manual creation of Rust entities. However, this possibility remains
132//! open yet not encouraged.
133//!
134//! All entities optionally support [Serde](https://serde.rs) and are thread-safe.
135//!
136//! # Errors
137//!
138//! All errors are variants (or sub-variants) of [`Error`](errors::Error). Fallible functions and methods return
139//! [`Result`] type.
140//!
141//! # Feature Flags
142//!
143#![doc = document_features::document_features!()]
144//
145#![warn(missing_docs)]
146#![deny(rustdoc::broken_intra_doc_links)]
147#![doc(
148 html_logo_url = "https://gitlab.com/mavka/libs/mavinspect/-/raw/main/avatar.png?ref_type=heads",
149 html_favicon_url = "https://gitlab.com/mavka/libs/mavinspect/-/raw/main/avatar.png?ref_type=heads"
150)]
151
152pub mod parser;
153#[doc(inline)]
154pub use parser::Inspector;
155
156pub mod errors;
157pub mod protocol;
158pub mod utils;