vu64 0.3.0

variable length encode/decode for a 64-bits integer
Documentation
# vu64 Library Design

## 1. Overview

The `vu64` library provides a variable-length integer encoding scheme for `u64` and `i64` values. The goal is to represent integers using a smaller number of bytes than their fixed-size counterparts, which is particularly useful for data serialization and network protocols where space is a concern.

## 2. Core Components

### 2.1. `Vu64` Struct

The central data structure is `Vu64`, which represents a variable-length encoded integer. It contains two fields:

*   `length`: A `u8` indicating the number of bytes used for the encoded integer (from 1 to 9).
*   `bytes`: A `[u8; 9]` array holding the encoded bytes.

This struct implements `AsRef<[u8]>` for easy access to the encoded byte slice.

### 2.2. Encoding and Decoding Functions

#### 2.2.1. `encode(value: u64) -> Vu64`

This function takes a `u64` value and returns a `Vu64` struct containing the variable-length encoded representation. The encoding scheme is as follows:

| Prefix     | Precision | Total Bytes |
|------------|-----------|-------------|
| `0xxxxxxx` | 7 bits    | 1 byte      |
| `10xxxxxx` | 14 bits   | 2 bytes     |
| `110xxxxx` | 21 bits   | 3 bytes     |
| `1110xxxx` | 28 bits   | 4 bytes     |
| `11110xxx` | 35 bits   | 5 bytes     |
| `111110xx` | 42 bits   | 6 bytes     |
| `1111110x` | 49 bits   | 7 bytes     |
| `11111110` | 56 bits   | 8 bytes     |
| `11111111` | 64 bits   | 9 bytes     |

To optimize performance, the `encoded_len` function uses a lookup table (`ENCODED_LEN_TBL`) to determine the required number of bytes based on the number of leading zeros in the input value.

#### 2.2.2. `decode(bytes: &[u8]) -> Result<u64, Error>`

This function takes a byte slice containing a `vu64`-encoded value and returns a `Result` with either the decoded `u64` value or an `Error` if the input is invalid. The `decoded_len` function determines the expected length from the first byte of the input.

### 2.3. Signed Integer Handling

Signed integers (`i64`) are supported through the `signed` module, which uses zigzag encoding to map `i64` values to `u64` values. This allows the same variable-length encoding logic to be used for both signed and unsigned integers.

*   `signed::zigzag::encode(value: i64) -> u64`
*   `signed::zigzag::decode(encoded: u64) -> i64`

### 2.4. I/O Integration

When the `io` feature is enabled, the `io` module provides the `ReadVu64` and `WriteVu64` traits, which extend `std::io::Read` and `std::io::Write` respectively. These traits provide methods for reading and writing `vu64` and `vi64` values directly from/to I/O streams.

*   `read_and_decode_vu64(&mut self) -> Result<u64>`
*   `encode_and_write_vu64(&mut self, value: u64) -> Result<()>`
*   `read_and_decode_vi64(&mut self) -> Result<i64>`
*   `encode_and_write_vi64(&mut self, value: i66) -> Result<()>`

### 2.5. Error Handling

The `Error` enum defines the possible errors that can occur during decoding:

*   `Truncated`: The input byte slice is shorter than expected.
*   `RedundantEncode`: The input value is a redundant encoding.

## 3. Module Structure

*   `lib.rs`: The root of the crate, defining the `Vu64` struct, the core `encode` and `decode` functions, and the `Error` enum. It also contains the `io` and `signed` modules.
*   `io.rs`: Contains the I/O traits and their implementations. This module is conditionally compiled based on the `io` feature.
*   `signed.rs`: Contains the logic for handling signed integers, including the `zigzag` submodule.

## 4. Dependencies

The library has no external dependencies and relies only on the Rust standard library (`std::core` and `std::io`).