mojo/public/rust/mojom_value_parser/README.md
This crate contains an implementation of a safe, simple, and generic Mojom parser and deparser written in Rust. Its job is to translate between Rust types and binary data that was encoded using the Mojom Wire Format. It is strongly recommended to understand, or at least skim, the wire format before working with the parsing code.
Note: Since the parser targets binary encoded data, parsing and deparsing can also be referred to as deserialization and serialization, respectively. The term "parsing" is used throughout this crate mostly as a historical artifact. Everything in this documentation that refers to the parser also applies to the deparser.
The primary goals for this parser are:
Note that performance is explicitly a non-goal; we'd certainly like it to be fast, but having comprehensible code is paramount, and highly optimized parsers are frequently much harder to understand. In the future, we may implement a new parser with an emphasis on speed, using this one as a reference.
Note that since this parser is abstract, it has significantly lower binary size impact than one which generated highly-specialized code for each individual type.
The parser centers around the concept of a Mojom Value, which is any value
that can be described in a Mojom file (e.g. uint32, a user-defined struct, etc).
The parser captures this using a MojomValue type, which is capable of
representing any such value:
// ast.rs:
pub enum MojomValue {
Bool(bool),
Int8(i8),
UInt8(u8),
Struct(Vec<MojomValue>),
...
}
For example, the value Foo { x: 1u8, y: true } corresponds to
Struct(vec![UInt8(1), Bool(true)]).
The MojomValue type serves as an intermediary between concrete Rust types
(like Foo), and encoded binary data ([u8]). In order to parse a value,
we first create a MojomValue from the data, and then convert that into a
specified Rust type. Deparsing is the same, but in the opposite direction:
Foo <---> MojomValue <---> [u8]
Because the Mojom wire format is not self-describing, a given binary message
could correspond to many different possible MojomValues. Therefore, when
parsing, we need to know the expected type of the data in the message, so we
know how to interpret the bits. To accommodate this, we define a MojomType
type which mirrors MojomValue:
// ast.rs:
pub enum MojomType {
Bool,
Int8,
UInt8,
Struct(Vec<MojomType>),
...
}
The Foo value above would map to the MojomType Struct(vec![UInt8, Bool]).
Unfortunately, the wire format is not a straightforward serialization; there are
various optimizations to the encoded format to e.g. save space. Therefore, we
additionally define a MojomWireType type, which specifies the on-the-wire
representation of a given MojomType. This type is used as an input to the
parsing and deparsing functions.
The packing algorithm in pack.rs is responsible for converting a MojomType
into the corresponding MojomWireType.
The process of converting Rust values to MojomValues is managed by the
MojomParse trait (parsing_trait.rs). The trait provides functions for
MojomType that corresponds to the Rust type.MojomValue (infallible).MojomValue to the value of the Rust type.Step (3) may fail if the MojomValue has the wrong type; for example, if we
tried to convert MojomValue::Int8(3) to a Foo (which is a Struct).
The MojomParse trait is automatically implemented for most types (primitives
and important builtins like vectors). For structs and enums, it can be derived
using a proc macro (parsing_attribute.rs).
This is the actual parsing/deparsing step (parse_values.rs, deparse_values.rs).
Both take the wire type as one of the inputs; deparsing additionally takes the
MojomValue to be serialized, while parsing instead produces a MojomValue.
Both parsing and deparsing proceed by inspecting the wire type to determine what the next thing on the wire should be. Deparsing looks up that part of the value and writes it to the message, whereas parsing reads the next N bytes and interprets them according to the wire type.
For more information about parsing and deparsing, see the relevant files, and make sure to read over the Mojom Wire Format beforehand.
Logically, this directory contains a single mojom_parser crate, but it's
split into several internal crates for build-system reasons.
The crates are:
mojom_parser (publicly visible):
mojom_parser_core (internal):
parsing_attribute:
parsing_trait.rs.mojom_parser_unittests:
test_mojomparse.rs