Crate fidl_next_codec

Source
Expand description

Encoding and decoding support for FIDL.

This crate provides a number of types and traits related to encoding and decoding FIDL types:

§Encoding

Here, “encoding” refers to the process of converting a Rust value to an encoded FIDL message. This process is captured in the Encode trait, which is parameterized over an encoder.

§Encodable types

Encoding a type relies on two primary traits:

  • Encodable is the most fundamental trait for encodable types. It specifies the encoded form of the type with the associated Encoded type. That encoded form is its wire type which must implement Wire.
  • Whereas Encodable specifies the wire type something encodes into, Encode does the actual encoding. Encode is parameterized over the encoder used to encode the type.

These traits are all you need to encode basic FIDL values. For more specialized encoding, some types may implement these specialized encoding traits as well:

§Encoding optional types

EncodableOption is a variant of Encodable which specifies how optional values of a type should be encoded. Most FIDL types are boxed when optional, which places the encoded value out-of-line. However, optional strings, vectors, unions, and handles are not boxed when optional. Instead, they have special optional wire types like WireOptionalString and WireOptionalVector which are optimized to save space on the wire. Implementing EncodableOption allows Options of a type to be encoded.

Implementing EncodableOption is optional, and only required if you encode an Option of your type. The generated bindings will always generate an implementation of EncodableOption for its types.

EncodeOption is the variant of Encode for EncodableOption.

§Encoding by reference

EncodeRef is a variant of Encode for types which can be encoded by reference. Encode encodes by value - it consumes the value being encoded. This allows Encode to encode resource types, which cannot be duplicated because they contain resources like handles. By contrast, EncodeRef does not consume the value being encoded, and can only be implemented for non-resource types. EncodeRef allows for more flexible and efficient encoding for many types.

Optional types can also support encoding by reference with the EncodeOptionRef trait.

§Encoders

Encodable types may only support encoding with specific kinds of encoders. They express these constraints by bounding the E type when implementing Encode<E> to require that the encoder implements some important traits. This crate provides the most fundamental encoder traits:

  • Most FIDL types require encoders to implement Encoder so that they can write out-of-line data. Strings, vectors, and tables are all examples of types which write out-of-line data. The EncoderExt extension trait provides useful methods for encoders when it is brought into scope (use fidl_next::EncoderExt as _).
  • Types containing Fuchsia handles can only be encoded by encoders which implement HandleEncoder.
  • The InternalHandleEncoder trait is an implementation detail. FIDL envelopes, which are used by tables and unions, may contain encoded types that the decoder doesn’t recognize. If a decoder encounters an envelope containing a type it doesn’t recognize, it needs to ignore the data and skip any handles it contained. To skip the correct number of handles, envelopes need to track the number of handles their value encoded. This is the case even if the envelope doesn’t contain any types which contain handles. InternalHandleEncoder provides this functionality to envelopes without requiring the encoder to actually support encoding handles.

An implementation of Encoder is provided for Vec<Chunk>.

§Decoding

Here, “decoding” has a very specific meaning. It refers to the process of validating and rewriting a buffer of Chunks to ensure it contains a valid Wire type. This definition is narrow, and does not include converting a wire type to a natural type.

The process of decoding is captured in the Decode trait. Like encoding, Decode is parameterized over a decoder.

§Decodable types

Types which implement Decode must first implement Wire to guarantee that their representation conforms to the requirements of the FIDL wire format specification. Then, they can specify how to validate and decode their wire form with the decode method.

decode needs to do three things to be correct:

  1. Verify that the encoded bytes are valid for the type. For bools, this means verifying that the encoded byte is either exactly 0 or exactly 1. If the encoded bytes are not valid for the type, decode must return an error.
  2. Reify pointers by decoding any out-of-line data and replacing presence indicators with the value of a pointer to that decoded data.
  3. Move resources from the decoder into the buffer. On the wire, handles are replaced with a presence indicator. They are transported separately by the transport because they require special handling.

Note that decode only manipulates data in-place, and only returns whether it succeeded or failed.

§Decoders

Like encoding, some types may only support encoding with specific types of decoders. We express these constraints by bounding the D type when implementing Decode<D> to require that the decoder implements some important traits:

  • Most FIDL types require decoders to implement Decoder so that they can decode out-of-line data. The DecoderExt extension trait provides useful methods for decoders when it is brought into scope (use fidl_next::DecoderExt as _).
  • Types containing Fuchsia handles can only be decoded by decoders which implement HandleDecoder.
  • Like encoding, the InternalHandleDecoder trait is an implementation detail for FIDL envelopes.

An implementation of Decoder is provided for &mut [Chunk].

§Committing

Decoding a wire type can fail at any point, even after resources have been taken out of the decoder. This presents a problem: partially-decoded values cannot be dropped, but may contain resources that must be dropped.

To solve this problem, taking a resource from a decoder happens in two phases:

  1. While decoding the resource is copied from the decoder into the buffer. The resource is left in the decoder.
  2. After decoding finishes successfully, the decoder is committed. Calling commit semantically completes moving the resources from the decoder into the buffer.

If decoding fails before commit is called, the decoder remains responsible for dropping the taken resources. After commit is called, the wire value is responsible for dropping the taken resources.

§Wire types

FIDL types which are used in-place without copying them out of the buffer implement Wire and are called “wire types”. Wire is an unsafe trait which bundles together the necessary guarantees and functional machinery for wire types. The most important thing it does is promise that the implementing type follows any layout requirements for FIDL’s wire types.

§Primitives

The FIDL wire specification requires “natural alignment” for wire primitives, which means that wire primitives must have alignment equal to their size. A four-byte int32 must be four-aligned, and so may differ from Rust’s native i32 type. To accommodate these differences, multibyte primitive types have special wire forms. Single-byte primitive types have the same natural and wire types.

FIDL typeNatural typeWire type
boolboolbool
int8i8i8
int16i16WireI16
int32i32WireI32
int64i64WireI64
uint8u8u8
uint16u16WireU16
uint32u32WireU32
uint64u64WireU64
float32f32WireF32
float64f64WireF64

All wire primitives implement Deref and dereference to their native primitive types.

§Containers

This crate provides wire types for containers supported by FIDL:

FIDL typeNatural typeWire type
box<T>Option<T>WireBox<T>
array<T, N>[T; N][T; N]
vector<T>Vec<T>WireVector<T>
stringStringWireString

§Lifetimes

Wire types with out-of-line data may contain pointers to other parts of a decoded buffer, and so cannot be allowed to outlive that decoded buffer. As a result, wire types are parameterized over the lifetime of the decoder they are contained in (typically named 'de). This lifetime isn’t important when reading data with wire types, but can impose important constraints when moving wire types and converting them to natural types.

After decoding, shared references to wire types can be obtained and used without any restrictions. These shared references allow reading the data from wire types, and provide all of the functionality required for handle-less FIDL.

However, in order to move resources like handles out of wire types, wire values must be taken from the decoder. Taking a wire type out of a decoder is an all-or-nothing operation - you must take the entire decoded wire value from a decoder, and it must be moved or dropped before the decoder can be moved or dropped. You can think of taking the wire value as sticking the decoder in place until the wire value is converted to a natural type or dropped. This means that for FIDL protocols, you must take the entire received FIDL message.

When wire values are taken out of a decoder, they are parameterized over the lifetime of the decoder (usually 'de) to prevent the decoder from being dropped. These values can be treated like ordinary Rust values.

§Conversion to natural types

Natural types can support conversion from a wire type by implementing FromWire. This trait has a from_wire method which parallels From::from and implements conversion from some wire type. Like Encode and Decode, the FromWireOption variant allows types to be converted from wire optional types.

Natural types that can be converted from a reference to a wire type (i.e. without moving the wire type) may implement FromWireRef. Similarly for options, the FromWireOptionRef trait allows options to be converted from a reference to a wire type.

Re-exports§

pub use self::decoder::Decoder;
pub use self::decoder::DecoderExt;
pub use self::encoder::Encoder;
pub use self::encoder::EncoderExt;

Modules§

decoder
The core Decoder trait.
encoder
The core Encoder trait.
fuchsia
Fuchsia-specific extensions to the FIDL codec.

Macros§

bitflags
Generate a flags type.
chunks
Returns a slice of chunks with the same bytewise value as the given bytes.
munge
Destructures a type into

Structs§

CopyOptimization
An optimization hint about whether the conversion from T to U is equivalent to copying the raw bytes of T.
Decoded
A decoded value and the decoder which contains it.
IntoIter
An iterator over the items of a WireVector.
RawWireUnion
A raw FIDL union
Slot
An initialized but potentially invalid value.
WireBox
A boxed (optional) FIDL value.
WireF32
A wire-encoded f32
WireF64
A wire-encoded f64
WireI16
A wire-encoded i16
WireI32
A wire-encoded i32
WireI64
A wire-encoded i64
WireOptionalString
An optional FIDL string
WireOptionalVector
An optional FIDL vector
WireResult
A FIDL result union.
WireString
A FIDL string
WireTable
A FIDL table
WireU16
A wire-encoded u16
WireU32
A wire-encoded u32
WireU64
A wire-encoded u64
WireVector
A FIDL vector

Enums§

DecodeError
Errors that can be produced when decoding FIDL messages.
EncodeError
Errors that can be produced while encoding FIDL messages.

Constants§

CHUNK_SIZE
FIDL alignment, used for buffer alignment to ensure decoding in-place is possible.

Traits§

Decode
Decodes a value from the given slot.
Encodable
A type which can be encoded as FIDL.
EncodableOption
A type which can be encoded as FIDL when optional.
Encode
Encodes a value.
EncodeOption
Encodes an optional value.
EncodeOptionRef
Encodes an optional reference.
EncodeRef
Encodes a reference.
FromWire
A type which is convertible from a wire type.
FromWireOption
An optional type which is convertible from a wire type.
FromWireOptionRef
An optional type which is convertible from a reference to a wire type.
FromWireRef
A type which is convertible from a reference to a wire type.
Wire
A FIDL wire type.

Type Aliases§

Chunk
A group of eight bytes, aligned to an 8-byte boundary.

Unions§

WireEnvelope
A FIDL envelope
WirePointer
A raw FIDL pointer