---
# System prepended metadata

title: Zerocopy Ecosystem Overview

---

# Zerocopy Ecosystem Overview

## Issue tracking
- fxbug.dev
- cs.opensource.google/fuchsia
- Components:
  - Connectivity>Libraries>net_types
  - Connectivity>Libraries>packet
  - Connectivity>Libraries>packet-formats

## Omnibus Build of Packet Dependencies
Add to this.
```
fx format-code && fx build src/connectivity/network/netstack3/core:{netstack3-core-instrumented,netstack3-core,netstack3-core-test-package,netstack3-core-testutils,netstack3-core-benchmarks,fuzz-single-device}
```

## Things We're Doing
- [ ] Remove `nonzero!` macro.
- [ ] Change `outer` argument of `Serialier` to `PacketConstraints`.
- [ ] 

## Things we need
- update documentation
- long tail of little sharp edges
- open q: when to publish
    - a: bias for publishing earlier than later
- fuchsia-specific stuff that needs to be disentangled
- most important crates:
    - net_types
    - packet
    - packet-formats


## Miscellany
- https://fuchsia-docs.firebaseapp.com/rust/fuchsia_component/index.html

```shell
$ fx set core.x64 --no-ccache --cargo-toml-gen
$ fx build src/lib/network/packet:packet
# Might not need to do this line every time
$ fx build build/rust:cargo_toml_gen
$ fx gen-cargo //src/lib/network/packet:packet
```

## TODOs by crate

### Packet

### Patchsets
- ~~[[packet] Simplify execution of Serializers](https://fuchsia-review.googlesource.com/c/fuchsia/+/861377)~~
- ~~[[packet] Rename and simplify `SerializeBuffer](https://fuchsia-review.googlesource.com/c/fuchsia/+/862010)~~
- ~~[[packet] Simplify buffer trait hierarchy](https://fuchsia-review.googlesource.com/c/fuchsia/+/862776)~~
- ~~[[packet] Merge SerializeBuffer into GrowBufferMut](https://fuchsia-review.googlesource.com/c/fuchsia/+/874198)~~

#### Clean up trait hierarchy

- Rename `FragmentedBuffer` to `MaybeFragmentedBuffer`?
- Move `Buffer`/`BufferMut` into N3
- Add `testutil` module which provides tests that validate buffer implementations; mention this module in the docs for all buffer traits

#### Improve docs

- `#![deny(missing_docs)]`
- In `ParsablePacket::parse`'s `Padding` docs section, the phrase "consume any post-packet padding from the buffer's suffix" is misleading - it should be something more like "from the body and added to the suffix"
- Consider renaming `encapsulate` to `encapsulate_in` or `nest_in` or similar
- Consider renaming `Nested` now that it is only used for `Serializers`
- In `GrowBuffer`:
  - This sentence is misleading: "The body of the buffer can shrink or grow as allowed by the capacity as packets are parsed or serialized." It is not guaranteed that a `GrowBuffer` can shrink.
  - Clarify "guarantees never to discard"
  - `undo_parse` can panic, but the docs claim it can't
- Add doc comment to `Serializer`

#### Impelemntation cleanup

- In `alloc_no_reuse`, change the following line to use checked arithmetic?
  ```
  let need_capacity = prefix + body + suffix;
  ```

#### Miscellaneous
- Move `BufferProvider::alloc_no_reuse` to `BufferAlloc`? It was introduced by Zeling in https://fxrev.dev/786703
- Consider verifying behavior using [flux](https://github.com/flux-rs/flux)
- Make functions and methods `const`
- Merge N3's `transport::tcp::buffer::SendPayload` into `packet`?
- There should be an extension trait on slices that provides the ability to read and write zerocopy objects (e.g., like `write_obj_front`)
- Remove getters on `ParseMetadata` now that its fields are `pub`?
- Make sure naming is consistent (traits use full words and types use abbreviated words)
- Consolodate `zero` and `zero_iter`
- Consider using `either` crate instead of custom `Either` buffer type
- Consider replacing `ByteSliceInnerPacketBuilder` with a blanket impl
- Combine `Either` and `EitherSerializer`?
- Make `PacketConstraints: Copy`

## Hints that Josh gave Jack for implementing UDP
- Start with parsing; it's easier than serializing
- Implement the `ParsablePacket` trait
- For parsing, take a look at what the `BufferView` trait gives you
- For ease of implementation, start with `ParseArgs = ()`
- For generating the body, use `buffer.into_rest()`
- For `ParsablePacket::parse_metadata`, the body length field is the framework's notion of body length, not (necessarily) the length field from the UDP header
- "...", the body length is `self.body.len()`, not 0
- After Jack started implementing `PacketBuilder` for `UdpPacket`: Your `PacketBuilder` type does not need to be the same as your `ParsablePacket` type
- Think of a `PacketBuilder` as a builder - just whatever information is necessary to perform serialization
- Just introduce a new `UdpPacketBuilder` type which contains only those fields which you can't compute on the fly
- After Jack suggested putting a body field in the `UdpPacketBuilder` type: Look at the `SerializeBuffer` docs (my thinking was to dissuade him from this and point him towards the fact that the `SerializeBuffer` already has access to the body in the buffer)
- Remember that it is the caller's responsibility to provide the body - `PacketBuilder` doesn't know about it until `serialize` is called

## Potential future directions
- If we use GATs to support a type parameter that represents mutability, we could do something like:
  ```rust
  struct UdpPacket<'a, M: Mutability> {
      header: Ref<'a, M, UdpHeader>,
      body: Ref<'a, M, [u8]>,
  }
  ```
- Make `Serializer` methods which take a `PacketBuilder`/`PacketConstraints` `#[doc(hidden)]` (unless we think consumers would ever want to implement `Serializer`?)


## Concepts

### Buffers

A sequence of bytes logically segmented into a:
- prefix
- body
- suffix

The total size of these segments is the `capacity` of the buffer.

The size of the body is the `length` of the buffer.

## Before
```graphviz
digraph G {
    Buffer [tooltip="A byte buffer used for parsing that can grow back to its original size."];
    Buffer -> GrowBuffer, ParseBuffer [dir=back];

    BufferMut [tooltip="A byte buffer used for parsing and serialization."];
    BufferMut -> TargetBuffer, ParseBufferMut, Buffer [dir=back];
    
    //BufferView [tooltip="A view into a ShrinkBuffer."];
    //BufferView -> Sized, "AsRef<[u8]>" [dir=back];
    
    //BufferViewMut [tooltip="A mutable view into a Buffer."];
    //BufferViewMut -> BufferView, "AsMut<[u8]>" [dir=back];
    
    ContiguousBuffer [tooltip="A buffer that is contiguous in memory."];
    ContiguousBuffer -> "AsRef<[u8]>" [dir=back];
    
    ContiguousBufferImpl [tooltip="A helper trait to implement FragmentedBuffer and ContiguousBuffer for any type that is AsRef<[u8]>."];
    ContiguousBufferImpl -> "AsRef<[u8]>" [dir=back];
    
    ContiguousBufferMut [tooltip="A mutable buffer that is contiguous in memory."];
    ContiguousBufferMut -> ContiguousBuffer, "AsMut<[u8]>" [dir=back];
    
    ContiguousBufferMutImpl [tooltip="A helper trait to implement FragmentedBufferMut and ContiguousBufferMut for any type that is AsMut<[u8]>."];
    ContiguousBufferMutImpl -> ContiguousBuffer, "AsMut<[u8]>" [dir=back];
    
    //Fragment [tooltip="A single byte slice fragment in a FragmentedByteSlice."];
    //Fragment -> ByteSlice [dir=back];
    
    FragmentedBuffer [tooltip="A buffer that may be fragmented in multiple parts which are discontiguous in memory."];
    
    FragmentedBufferMut [tooltip="A FragmentedBuffer with mutable access to its contents."];
    FragmentedBufferMut -> FragmentedBuffer [dir=back];
    
    //FromRaw [tooltip="A packet that can be created from a raw form."];
    //FromRaw -> Sized [dir=back];
    
    GrowBuffer [tooltip="A buffer that can grow its body by taking space from its prefix and suffix."];
    GrowBuffer -> FragmentedBuffer [dir=back];
    
    GrowBufferMut [tooltip="A GrowBuffer which provides mutable access to its contents."];
    GrowBufferMut -> GrowBuffer, FragmentedBufferMut [dir=back];
    
    //ParsablePacket [tooltip="A packet which can be parsed from a buffer."];
    //ParsablePacket -> Sized [dir=back];
    
    ParseBuffer [tooltip="A byte buffer used for parsing."];
    ParseBuffer -> ShrinkBuffer, ContiguousBuffer [dir=back];
    
    ParseBufferMut [tooltip="A ParseBuffer which provides mutable access to its contents."];
    ParseBufferMut -> ParseBuffer, FragmentedBufferMut, ContiguousBufferMut [dir=back];
    
    ReusableBuffer [tooltip="A byte buffer that can be reused."];
    ReusableBuffer -> TargetBuffer, ShrinkBuffer [dir=back];
    
    ShrinkBuffer [tooltip="A buffer that can reduce its size."];
    ShrinkBuffer -> FragmentedBuffer [dir=back];
    
    TargetBuffer [tooltip="A buffer that can be serialized into."];
    TargetBuffer -> GrowBufferMut [dir=back];
}
```

## After
```graphviz
digraph G {    
    
    //BufferView [tooltip="A view into a ShrinkBuffer."];
    //BufferView -> Sized, "AsRef<[u8]>" [dir=back];
    
    //BufferViewMut [tooltip="A mutable view into a Buffer."];
    //BufferViewMut -> BufferView, "AsMut<[u8]>" [dir=back];
    
    ContiguousBuffer [tooltip="A buffer that is contiguous in memory."];
    ContiguousBuffer -> FragmentedBuffer, "AsRef<[u8]>" [dir=back];
    
    ContiguousBufferMut [tooltip="A mutable buffer that is contiguous in memory."];
    ContiguousBufferMut -> ContiguousBuffer, FragmentedBufferMut, "AsMut<[u8]>" [dir=back];
    
    //Fragment [tooltip="A single byte slice fragment in a FragmentedByteSlice."];
    //Fragment -> ByteSlice [dir=back];
    
    FragmentedBuffer [tooltip="A buffer that may be fragmented in multiple parts which are discontiguous in memory."];
    
    GrowBuffer [tooltip="A buffer that can grow its body by taking space from its prefix and suffix."];
    GrowBuffer -> FragmentedBuffer [dir=back];
    
    FragmentedBufferMut [tooltip="A FragmentedBuffer with mutable access to its contents."];
    FragmentedBufferMut -> FragmentedBuffer [dir=back];
    
    //FromRaw [tooltip="A packet that can be created from a raw form."];
    //FromRaw -> Sized [dir=back];
    
    
    GrowBufferMut [tooltip="A GrowBuffer which provides mutable access to its contents."];
    GrowBufferMut -> GrowBuffer, FragmentedBufferMut [dir=back];
    
    //ParsablePacket [tooltip="A packet which can be parsed from a buffer."];
    //ParsablePacket -> Sized [dir=back];
    
    ParseBuffer [tooltip="A byte buffer used for parsing."];
    ParseBuffer -> ShrinkBuffer, ContiguousBuffer [dir=back];
    
    ParseBufferMut [tooltip="A ParseBuffer which provides mutable access to its contents."];
    ParseBufferMut -> ParseBuffer, ContiguousBufferMut [dir=back];
    
    ReusableBuffer [tooltip="A byte buffer that can be reused."];
    ReusableBuffer -> SerializeBuffer, ShrinkBuffer [dir=back];
    
    ShrinkBuffer [tooltip="A buffer that can reduce its size."];
    ShrinkBuffer -> FragmentedBuffer [dir=back];
    
    SerializeBuffer [tooltip="A buffer that can be serialized into."];
    SerializeBuffer -> GrowBufferMut [dir=back];
}
```



## Naming `packet`

### `buffer`
pros:
- boop

cons:
- moop