prettier-bytes 0.2.1

A blazingly fast and safe, zero-allocation, `no_std`-compatible byte formatter.
Documentation
# `prettier-bytes`

[![Crates.io](https://img.shields.io/crates/v/prettier-bytes)](https://crates.io/crates/prettier-bytes)
[![Documentation](https://docs.rs/prettier-bytes/badge.svg)](https://docs.rs/prettier-bytes)
[![License](https://img.shields.io/crates/l/prettier-bytes)](https://spdx.org/licenses/MIT)
[![`no_std`](https://img.shields.io/badge/no__std-compatible-success.svg)](#)

A blazingly fast and safe, zero-allocation, `no_std`-compatible byte formatter.

`prettier-bytes` provides the API to format raw byte sizes into human-readable strings (e.g., "1.50 MB", "2.34 GiB") without using heap allocations, floating-point math, or dynamic CPU division. It is designed for maximum throughput in microcontrollers, OS kernels, and high-performance CLIs.

## ✨ Features

- **Zero Allocation:** Operates entirely on a 16-byte stack array. It does not use the `alloc` crate.
- **Mathematically Panic-Free:** Built under a paranoid `#![forbid(...)]` linting regime. Zero slice indexing, zero `unwrap()`, zero `expect()`. The compiler is mathematically guaranteed to never insert bounds-check panic branches.
- **Hardware Optimized:** Bypasses incredibly slow 64-bit dynamic hardware division. It relies purely on 1-cycle bitwise shifts for Binary parsing, and compile-time reciprocal multiplication for SI parsing.
- **100% Safe Rust:** Forbids `unsafe` code entirely.
- **`no_std` Native:** Works out of the box in bare-metal environments.

## 🚀 Quick Start

```rust
use prettier_bytes::{ByteFormatter, Standard, Unit};

fn main() {
    // Configure the formatter once
    let formatter = ByteFormatter::new()
        .standard(Standard::Binary)
        .unit(Unit::Bytes)
        .space(true);

    // Format your value!
    let size = formatter.format(1048576);

    // Implements `fmt::Display` for zero-friction printing
    println!("File size: {size}"); // Outputs: "1.00 MiB"
}
```

## 🛠 Usage & API

The `ByteFormatter` uses a builder pattern to configure your output. Once configured, you can call `.format(value)` to calculate the size and store it inside a tiny `[u8; 16]` buffer. You have full control over the standard, units, and spacing.

### Standards (SI vs Binary)

```rust
use prettier_bytes::{ByteFormatter, Standard};

let val = 2_500_000;

// Base 1000 (SI Standard) -> kB, MB, GB...
let si = ByteFormatter::new()
    .standard(Standard::SI)
    .format(val);

assert_eq!(si.as_str().unwrap(), "2.50 MB");

// Base 1024 (IEC/Binary Standard) -> KiB, MiB, GiB...
let bin = ByteFormatter::new()
    .standard(Standard::Binary)
    .format(val);

assert_eq!(bin.as_str().unwrap(), "2.38 MiB");
```

### Units (Bytes vs Bits)

```rust
use prettier_bytes::{ByteFormatter, Standard, Unit};

let val = 2_500_000;

// Capital 'B' for Bytes
let bytes = ByteFormatter::new()
    .standard(Standard::SI)
    .unit(Unit::Bytes)
    .format(val);

assert_eq!(bytes.as_str().unwrap(), "2.50 MB");

// Lowercase 'b' for Bits
let bits = ByteFormatter::new()
    .standard(Standard::SI)
    .unit(Unit::Bits)
    .format(val);

assert_eq!(bits.as_str().unwrap(), "2.50 Mb");
```

### Zero-Cost Retrievals

If you are writing to a fast I/O stream, you don't even need to convert it to a string. You can extract the raw, formatted byte slice directly:

```rust
use prettier_bytes::{ByteFormatter, Standard, Unit};

let formatted = ByteFormatter::new()
    .standard(Standard::SI)
    .space(false)
    .format(1500);

// Instantly returns &[u8] for fast std::io::Write or embedded UART transmission
let raw_bytes = formatted.as_bytes();

assert_eq!(raw_bytes, b"1.50kB");
```

## 🏎 Under the Hood: Why is it so fast?

Most "human readable byte" formatting libraries follow this pattern:

1. Figure out the magnitude (Kilo, Mega, Giga).
2. Look up the divisor in an array.
3. Divide the value by the divisor dynamically at runtime (`val / divisor`).
4. Append to a `String`.

This is disastrous for performance. Array lookups risk bounds panics. Heap allocation (`String`) is slow. And worst of all, **dynamic 64-bit division is one of the slowest operations a CPU can do**, taking 15 to 40 clock cycles.

`prettier-bytes` flips this on its head:

1. It uses purely static `match` statements to figure out the magnitude.
2. For **Binary (base 1024)**, it replaces division entirely with bitwise shifts (`>>`) and masking (`&`), executing in a single clock cycle.
3. For **SI (base 1000)**, it feeds hardcoded literals into a macro, allowing the LLVM compiler to replace division with lightning-fast "reciprocal multiplication".
4. It iterates safely over a stack-allocated `[u8; 16]` to assemble the string.

The result is a completely flat, allocation-free assembly profile.

## ⚖️ License

This project is licensed under the [MIT License](https://spdx.org/licenses/MIT).