Module domain::base::octets

source ·
Expand description

Variable length octet sequences.

This module provides the basic traits that allow defining types that are generic over a variable length sequence of octets. It implements these traits for most commonly used types of such sequences and provides a few additional types for use in a no-std environment. In addition, it provides a few types and traits that make it easier to access data contained in such sequences.

Traits for Octet Sequences

There are two fundamental types of octet sequences. If a sequence is of a given size, we call it simply ‘octets.’ If the sequence is actually a buffer into which octets can be placed, it is called an octets builder.

Octets and Octets References

There is no special trait for octets, we simply use AsRef<[u8]> for immutable octets or AsMut<[u8]> if the octets of the sequence can be manipulated (but the length is still fixed). This way, any type implementing these traits can be used already. The trait OctetsExt has been defined to collect additional methods that aren’t available via plain AsRef<[u8]>.

A reference to an octets type implements OctetsRef. The main purpose of this trait is to allow cheaply taking a sub-sequence, called a ‘range’, out of the octets. For most types, ranges will be octet slices &[u8] but some shareable types (most notably bytes::Bytes) allow ranges to be owned values, thus avoiding the lifetime limitations a slice would bring.

One type is special in that it is its own octets reference: &[u8], referred to as an octets slice in the documentation. This means that you always use an octets slice irregardless whether a type is generic over an octets sequence or an octets reference. Because an octets slice is also a useful basis when only looking at some value without planning on keeping any ranges from it, most generic types provide a method for_slice that converts the value from whatever octets type it is currently generic over into an identical value atop a octets slice of that sequence.

The trait is separate because of limitations of lifetimes in traits. It has an associated type OctetsRef::Range that defines the type of a range. When using the trait as a trait bound for a generic type, you will typically bound a reference to this type. For instance, a generic function taking part out of some octets and returning a reference to it could be defined like so:


fn take_part<'a, Octets>(
    src: &'a Octets
) -> <&'a Octets as OctetsRef>::Range
where &'a Octets: OctetsRef {
    unimplemented!()
}

The where clause demands that whatever octets type is being used, a reference to it must be an octets ref. The return value refers to the range type defined for this octets ref. The lifetime argument is necessary to tie all these references together.

Octets Builders

Octets builders and their OctetsBuilder trait are comparatively straightforward. They represent a buffer to which octets can be appended. Whether the buffer can grow to accommodate appended data depends on the underlying type. Because it may not, all such operations may fail with a ShortBuf error.

The EmptyBuilder trait marks a type as being able to create a new, empty builder.

Conversion Traits

A series of special traits allows converting octets into octets builder and vice versa. They pair octets with their natural builders via associated types. These conversions are always cyclic, i.e., if an octets value is converted into a builder and then that builder is converted back into an octets value, the initial and final octets value have the same type.

Using Trait Bounds

When using these traits as bounds for generic types, always limit yourself to the most loose bounds you can get away with. Not all types holding octet sequences can actually implement all these traits, so by being to eager you may paint yourself into a corner.

In many cases you can get away with a simple AsRef<[u8]> bound. Only use an explicit OctetsRef bound when you need to return a range that may be kept around.

Serde Support

Serde supports native serialization of octets sequences. However, because of missing specialization, it has to serialize the octets slices and vec as literal sequences of u8s. If built with the serde feature enable, the two traits SerializeOctets and DeserializeOctets let types define serialization into octets sequences. Types that are generic over octets sequences can use these to implement serde’s Serialize and Deserialize traits.

Composing and Parsing

Octet sequences are often used to encode data, such as with the DNS wire format. We call the process of converting data into its octet sequence encoding ‘composing’ and the reverse process of reading data out of its encoded form ‘parsing.’ In order to make implementing these functions easier, the module contains a traits for types that can be composed or parsed as well as helper types for parsing.

Composing

Composing encoded data always happens directly into an octets builder. Any type that can be encoded as DNS wire data implements the Compose trait through which its values can be appened to the builder.

Parsing

Parsing is a little more complicated since encoded data may very well be broken or ambiguously encoded. The helper type Parser wraps an octets ref and allows to parse values from the octets. The trait Parse is implemented by types that can decode values from octets.

Octet Sequences for no_std Use

When using the crate without an allocator, creating octets sequences can be difficult. However, since DNS data is often limited in size, you can in many cases get away with using a octets array as the basis for an octets sequence. The crate provides a macro [octets_array!] to define such a type for specific array length. The octets module also contains a number of types defined via that module for typical array sizes.

Structs

Enums

Traits

  • A type that knows how to compose itself into an octets builder.
  • An octets builder that can be newly created empty.
  • An octets type that can be created from an octets builder.
  • An octets type that can be converted into an octets builder.
  • A buffer to construct an octet sequence.
  • An extension trait for octet sequences.
  • Convert a type from one octets type to another.
  • Convert a type from one octets type to another.
  • A reference to an octets sequence.
  • A type that can extract a value from a parser.

Type Definitions

  • A octets vector that doesn’t allocate for small sizes.