fidl_next_codec/
lib.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Encoding and decoding support for FIDL.
6//!
7//! This crate provides a number of types and traits related to encoding and decoding FIDL types:
8//!
9//! ## Encoding
10//!
11//! Here, "encoding" refers to the process of converting a Rust value to an encoded FIDL message.
12//! This process is captured in the [`Encode`] trait, which is parameterized over an _encoder_.
13//!
14//! ### Encodable types
15//!
16//! Encoding a type relies on two primary traits:
17//!
18//! - [`Encodable`] is the most fundamental trait for encodable types. It specifies the encoded form
19//!   of the type with the associated [`Encoded`](Encodable::Encoded) type. That encoded form is its
20//!   wire type which must implement [`Wire`].
21//! - Whereas `Encodable` specifies the wire type something encodes into, [`Encode`] does the actual
22//!   encoding. [`Encode`] is parameterized over the encoder used to encode the type.
23//!
24//! These traits are all you need to encode basic FIDL values. For more specialized encoding, some
25//! types may implement these specialized encoding traits as well:
26//!
27//! #### Encoding optional types
28//!
29//! [`EncodableOption`] is a variant of [`Encodable`] which specifies how optional values of a type
30//! should be encoded. Most FIDL types are [boxed](WireBox) when optional, which places the encoded
31//! value out-of-line. However, optional strings, vectors, unions, and handles are not boxed when
32//! optional. Instead, they have special optional wire types like [`WireOptionalString`] and
33//! [`WireOptionalVector`] which are optimized to save space on the wire. Implementing
34//! [`EncodableOption`] allows `Option`s of a type to be encoded.
35//!
36//! Implementing [`EncodableOption`] is optional, and only required if you encode an `Option` of
37//! your type. The generated bindings will always generate an implementation of [`EncodableOption`]
38//! for its types.
39//!
40//! [`EncodeOption`] is the variant of [`Encode`] for [`EncodableOption`].
41//!
42//! #### Encoding by reference
43//!
44//! [`EncodeRef`] is a variant of [`Encode`] for types which can be encoded by reference. [`Encode`]
45//! encodes by value - it consumes the value being encoded. This allows [`Encode`] to encode
46//! resource types, which cannot be duplicated because they contain resources like handles. By
47//! contrast, [`EncodeRef`] does not consume the value being encoded, and can only be implemented
48//! for non-resource types. [`EncodeRef`] allows for more flexible and efficient encoding for many
49//! types.
50//!
51//! Optional types can also support encoding by reference with the [`EncodeOptionRef`] trait.
52//!
53//! ### Encoders
54//!
55//! Encodable types may only support encoding with specific kinds of encoders. They express these
56//! constraints by bounding the `E` type when implementing [`Encode<E>`] to require that the encoder
57//! implements some important traits. This crate provides the most fundamental encoder traits:
58//!
59//! - Most FIDL types require encoders to implement [`Encoder`] so that they can write out-of-line
60//!   data. Strings, vectors, and tables are all examples of types which write out-of-line data.
61//!   The [`EncoderExt`] extension trait provides useful methods for encoders when it is brought
62//!   into scope (`use fidl_next::EncoderExt as _`).
63//! - Types containing Fuchsia handles can only be encoded by encoders which implement
64//!   [`HandleEncoder`](fuchsia::HandleEncoder).
65//! - The [`InternalHandleEncoder`](encoder::InternalHandleEncoder) trait is an implementation
66//!   detail. FIDL envelopes, which are used by tables and unions, may contain encoded types that
67//!   the decoder doesn't recognize. If a decoder encounters an envelope containing a type it
68//!   doesn't recognize, it needs to ignore the data and skip any handles it contained. To skip the
69//!   correct number of handles, envelopes need to track the number of handles their value encoded.
70//!   This is the case even if the envelope doesn't contain any types which contain handles.
71//!   [`InternalHandleEncoder`](encoder::InternalHandleEncoder) provides this functionality to
72//!   envelopes without requiring the encoder to actually support encoding handles.
73//!
74//! An implementation of [`Encoder`] is provided for `Vec<Chunk>`.
75//!
76//! ## Decoding
77//!
78//! Here, "decoding" has a very specific meaning. It refers to the process of validating and
79//! rewriting a buffer of [`Chunk`]s to ensure it contains a valid [`Wire`] type. This definition is
80//! narrow, and does not include converting a wire type to a natural type.
81//!
82//! The process of decoding is captured in the [`Decode`] trait. Like encoding, [`Decode`] is
83//! parameterized over a _decoder_.
84//!
85//! ### Decodable types
86//!
87//! Types which implement [`Decode`] must first implement [`Wire`] to guarantee that their
88//! representation conforms to the requirements of the FIDL wire format specification. Then, they
89//! can specify how to validate and decode their wire form with the [`decode`](Decode::decode)
90//! method.
91//!
92//! [`decode`](Decode::decode) needs to do three things to be correct:
93//!
94//! 1. Verify that the encoded bytes are valid for the type. For `bool`s, this means verifying that
95//!    the encoded byte is either exactly 0 or exactly 1. If the encoded bytes are not valid for the
96//!    type, `decode` **must** return an error.
97//! 2. Reify pointers by decoding any out-of-line data and replacing presence indicators with the
98//!    value of a pointer to that decoded data.
99//! 3. Move resources from the decoder into the buffer. On the wire, handles are replaced with a
100//!    presence indicator. They are transported separately by the transport because they require
101//!    special handling.
102//!
103//! Note that [`decode`](Decode::decode) only manipulates data in-place, and only returns whether it
104//! succeeded or failed.
105//!
106//! ### Decoders
107//!
108//! Like encoding, some types may only support encoding with specific types of decoders. We express
109//! these constraints by bounding the `D` type when implementing [`Decode<D>`] to require that the
110//! decoder implements some important traits:
111//!
112//! - Most FIDL types require decoders to implement [`Decoder`] so that they can decode out-of-line
113//!   data. The [`DecoderExt`] extension trait provides useful methods for decoders when it is
114//!   brought into scope (`use fidl_next::DecoderExt as _`).
115//! - Types containing Fuchsia handles can only be decoded by decoders which implement
116//!   [`HandleDecoder`](fuchsia::HandleDecoder).
117//! - Like encoding, the [`InternalHandleDecoder`](decoder::InternalHandleDecoder) trait is an
118//!   implementation detail for FIDL envelopes.
119//!
120//! An implementation of [`Decoder`] is provided for `&mut [Chunk]`.
121//!
122//! #### Committing
123//!
124//! Decoding a wire type can fail at any point, even after resources have been taken out of the
125//! decoder. This presents a problem: partially-decoded values cannot be dropped, but may contain
126//! resources that must be dropped.
127//!
128//! To solve this problem, taking a resource from a decoder happens in two phases:
129//!
130//! 1. While decoding the resource is copied from the decoder into the buffer. The resource is left
131//!    in the decoder.
132//! 2. After decoding finishes successfully, the decoder is [committed](Decoder::commit). Calling
133//!    `commit` semantically completes moving the resources from the decoder into the buffer.
134//!
135//! If decoding fails before `commit` is called, the decoder remains responsible for dropping the
136//! taken resources. After `commit` is called, the wire value is responsible for dropping the taken
137//! resources.
138//!
139//! ## Wire types
140//!
141//! FIDL types which are used in-place without copying them out of the buffer implement [`Wire`] and
142//! are called "wire types". [`Wire`] is an unsafe trait which bundles together the necessary
143//! guarantees and functional machinery for wire types. The most important thing it does is promise
144//! that the implementing type follows any layout requirements for FIDL's wire types.
145//!
146//! ### Primitives
147//!
148//! The FIDL wire specification requires "natural alignment" for wire primitives, which means that
149//! wire primitives must have alignment equal to their size. A four-byte `int32` must be
150//! four-aligned, and so may differ from Rust's native `i32` type. To accommodate these differences,
151//! multibyte primitive types have special wire forms. Single-byte primitive types have the same
152//! natural and wire types.
153//!
154//! | FIDL type     | Natural type  | Wire type     |
155//! | ------------- | ------------- | ------------- |
156//! | `bool`        | `bool`        | `bool`        |
157//! | `int8`        | `i8`          | `i8`          |
158//! | `int16`       | `i16`         | [`WireI16`]   |
159//! | `int32`       | `i32`         | [`WireI32`]   |
160//! | `int64`       | `i64`         | [`WireI64`]   |
161//! | `uint8`       | `u8`          | `u8`          |
162//! | `uint16`      | `u16`         | [`WireU16`]   |
163//! | `uint32`      | `u32`         | [`WireU32`]   |
164//! | `uint64`      | `u64`         | [`WireU64`]   |
165//! | `float32`     | `f32`         | [`WireF32`]   |
166//! | `float64`     | `f64`         | [`WireF64`]   |
167//!
168//! All wire primitives implement `Deref` and dereference to their native primitive types.
169//!
170//! ### Containers
171//!
172//! This crate provides wire types for containers supported by FIDL:
173//!
174//! | FIDL type     | Natural type  | Wire type         |
175//! | ------------- | ------------- | ----------------- |
176//! | `box<T>`      | `Option<T>`   | [`WireBox<T>`]    |
177//! | `array<T, N>` | `[T; N]`      | `[T; N]`          |
178//! | `vector<T>`   | `Vec<T>`      | [`WireVector<T>`] |
179//! | `string`      | `String`      | [`WireString`]    |
180//!
181//! ### Lifetimes
182//!
183//! Wire types with out-of-line data may contain pointers to other parts of a decoded buffer, and so
184//! cannot be allowed to outlive that decoded buffer. As a result, wire types are parameterized over
185//! the lifetime of the decoder they are contained in (typically named `'de`). This lifetime isn't
186//! important when reading data with wire types, but can impose important constraints when _moving_
187//! wire types and converting them to natural types.
188//!
189//! After decoding, shared references to wire types can be obtained and used without any
190//! restrictions. These shared references allow reading the data from wire types, and provide all of
191//! the functionality required for handle-less FIDL.
192//!
193//! However, in order to move resources like handles out of wire types, wire values must be taken
194//! from the decoder. Taking a wire type out of a decoder is an all-or-nothing operation - you must
195//! take the entire decoded wire value from a decoder, and it must be moved or dropped before the
196//! decoder can be moved or dropped. You can think of taking the wire value as sticking the decoder
197//! in place until the wire value is converted to a natural type or dropped. This means that for
198//! FIDL protocols, you must take the entire received FIDL message.
199//!
200//! When wire values are taken out of a decoder, they are parameterized over the lifetime of the
201//! decoder (usually `'de`) to prevent the decoder from being dropped. These values can be treated
202//! like ordinary Rust values.
203//!
204//! ### Conversion to natural types
205//!
206//! Natural types can support conversion from a wire type by implementing [`FromWire`]. This trait
207//! has a [`from_wire`](FromWire::from_wire) method which parallels `From::from` and implements
208//! conversion from some wire type. Like `Encode` and `Decode`, the [`FromWireOption`] variant
209//! allows types to be converted from wire optional types.
210//!
211//! Natural types that can be converted from a reference to a wire type (i.e. without moving the
212//! wire type) may implement [`FromWireRef`]. Similarly for options, the [`FromWireOptionRef`] trait
213//! allows options to be converted from a reference to a wire type.
214
215#![deny(
216    future_incompatible,
217    missing_docs,
218    nonstandard_style,
219    unused,
220    warnings,
221    clippy::all,
222    clippy::alloc_instead_of_core,
223    clippy::missing_safety_doc,
224    clippy::std_instead_of_core,
225    // TODO: re-enable this lint after justifying unsafe blocks
226    // clippy::undocumented_unsafe_blocks,
227    rustdoc::broken_intra_doc_links,
228    rustdoc::missing_crate_level_docs
229)]
230#![forbid(unsafe_op_in_unsafe_fn)]
231
232#[cfg(test)]
233#[macro_use]
234mod testing;
235
236mod chunk;
237#[cfg(feature = "compat")]
238mod compat;
239mod copy_optimization;
240mod decode;
241mod decoded;
242pub mod decoder;
243mod encode;
244pub mod encoder;
245mod from_wire;
246#[cfg(feature = "fuchsia")]
247pub mod fuchsia;
248mod primitives;
249mod slot;
250mod wire;
251
252pub use bitflags::bitflags;
253pub use munge::munge;
254
255pub use self::chunk::*;
256pub use self::copy_optimization::*;
257pub use self::decode::*;
258pub use self::decoded::*;
259pub use self::decoder::{Decoder, DecoderExt};
260pub use self::encode::*;
261pub use self::encoder::{Encoder, EncoderExt};
262pub use self::from_wire::*;
263pub use self::primitives::*;
264pub use self::slot::*;
265pub use self::wire::*;