1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! **MAVInspect** is a library for parsing MAVLink
//! [message definitions](https://github.com/mavlink/mavlink/tree/master/message_definitions/v1.0).
//!
//! <span style="font-size:24px">[🇺🇦](https://mavka.gitlab.io/home/a_note_on_the_war_in_ukraine/)</span>
//! [![`repository`](https://img.shields.io/gitlab/pipeline-status/mavka/libs/mavinspect.svg?branch=main&label=repository)](https://gitlab.com/mavka/libs/mavinspect)
//! [![`crates.io`](https://img.shields.io/crates/v/mavinspect.svg)](https://crates.io/crates/mavinspect)
//! [![`docs.rs`](https://img.shields.io/docsrs/mavinspect.svg?label=docs.rs)](https://docs.rs/mavinspect/latest/mavinspect/)
//! [![`issues`](https://img.shields.io/gitlab/issues/open/mavka/libs/mavinspect.svg)](https://gitlab.com/mavka/libs/mavinspect/-/issues/)
//!
//! # Usage
//!
//! Discover and parse MAVLink XML using [`Inspector`]:
//!
//! ```rust
//! use mavinspect::parser::Inspector;
//!
//! // Instantiate inspector and load XML definitions from several locations
//! let inspector = Inspector::builder()
//!     .set_sources(&[
//!         "./message_definitions/standard",
//!         "./message_definitions/extra",
//!     ])
//!     .set_include(&["crazy_flight"])
//!     .build()
//!     .unwrap();
//!   
//! // Parse all XML definitions
//! let protocol = inspector.parse().unwrap();
//!   
//! // Get `CrazyFlight` custom dialect
//! let crazy_flight = protocol.get_dialect_by_canonical_name("crazy_flight").unwrap();
//!
//! // Get `CRAZYFLIGHT_OUTCRY` message
//! let outcry_message = crazy_flight.get_message_by_name("CRAZYFLIGHT_OUTCRY").unwrap();
//! println!("\n`CRAZYFLIGHT_OUTCRY` message: {:#?}", outcry_message);
//! ```
//!
//! Here we obtain an instance of [`Protocol`](protocol::Protocol) that contains a collection of
//! dialects. Each [`Dialect`](protocol::Dialect) contains MAVLink [`enums`](protocol::Dialect::enums) and
//! [`messages`](protocol::Dialect::messages) as well as additional information (like version or dialect dependencies).
//!
//! # Dialects Naming
//!
//! To avoid collision between similar dialect names like `SomeDialect` and `some_dialect` in libraries which use
//! MAVInspect for code generation, we match dialect names up to `lower_snake_case`. This means that `SomeDialect`,
//! `SOME_DIALECT`, and `some_dialect` will be considered the same, while `somedialect` will be considered as a
//! different dialect. For example:
//!
//! ```rust
//! # use mavinspect::parser::Inspector;
//! let inspector_builder = Inspector::builder()
//!     // this is the original dialect name as it appears in the XML file name
//!     .set_include(&["SomeDialect"])
//!     // and this is a canonical name
//!     .set_include(&["some_dialect"]);
//! // both rules will lead to the same result since names will be converted to `some_dialect` upon matching
//! ```
//!
//! See details in [`Dialect::canonical_name`](protocol::Dialect::canonical_name).
//!
//! # Filtering
//!
//! It is possible to filter [`Protocol`](protocol::Protocol) and a specific [`Dialect`](protocol::Dialect) by messages,
//! enums, commands, and MAVLink [microservices](https://mavlink.io/en/services/). For example:
//!
//! ```rust
//! # use mavinspect::parser::Inspector;
//! # let inspector = Inspector::builder()
//! #     .set_sources(&["./message_definitions/standard"])
//! #     .set_include(&["common"])
//! #     .build().unwrap();
//! # let protocol = inspector.parse().unwrap();
//! use mavinspect::protocol::{Filter, Microservices};
//!
//! /* obtain protocol with `common` dialect */
//!
//! // Filter
//! let filtered_protocol = protocol.filtered(
//!     &Filter::by_microservices(Microservices::HEARTBEAT | Microservices::MISSION)
//!     .with_messages(&["FILE_TRANSFER_PROTOCOL"])
//!     .with_enums(&["GIMBAL_DEVICE_CAP_FLAGS"])
//!     .with_commands(&["MAV_CMD_SET_*"])
//! );
//! ```
//!
//! Check [`Filter`](protocol::Filter) for details.
//!
//! # Cargo Features
//!
//! * `serde` — add [Serde](https://serde.rs) support.
//! * `unstable` — unstable API features. These features can be changed at any moment and their usage in production
//!   environments is discouraged.
//!
//! # Protocol Specification API
//!
//! MAVLink entities are defined in the [`protocol`] module. The root of the specification is
//! [`Protocol`](protocol::Protocol) struct that contains a collection of [`Dialect`](protocol::Dialect). The latter
//! contains dialect metadata, [`messages`](protocol::Dialect::messages) and [`enums`](protocol::Dialect::enums).
//!
//! Most of the entities with complex validation rules and lots of parameters are using
//! [builder](https://rust-unofficial.github.io/patterns/patterns/creational/builder.html) instead of direct
//! instantiation (no constructors). We assume that library clients prefer to use XML definitions as a ground truth for
//! their dialects and are not very interested in manual creation of Rust entities. However, this possibility remains
//! open yet not encouraged.
//!
//! All entities optionally support [Serde](https://serde.rs) and are thread-safe.
//!
//! # Errors
//!
//! All errors are variants (or sub-variants) of [`Error`](errors::Error). Fallible functions and methods return
//! [`Result`] type.

#![warn(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![doc(
    html_logo_url = "https://gitlab.com/mavka/libs/mavinspect/-/raw/main/avatar.png?ref_type=heads",
    html_favicon_url = "https://gitlab.com/mavka/libs/mavinspect/-/raw/main/avatar.png?ref_type=heads"
)]

pub mod parser;
#[doc(inline)]
pub use parser::Inspector;

pub mod errors;
pub mod protocol;
pub mod utils;