# ZeroTree — zerocopy wrapper over ConstTree

## Мотивация

Для типов с trivial representation (`#[repr(C)]`, fixed layout) полноценный
`TypedTree` с Codec — overkill. `ZeroTree` — тонкая обёртка вокруг `ConstTree<K, V>`,
которая конвертирует `T <-> [u8; V]` через zerocopy (zero-cost transmute).

## Архитектура

```text
ZeroTree<K, V, D, T>
  └── ConstTree<K, V, D>
        └── SkipList<ConstNode<K, V, D::Loc>>
```

`D: Durability` — backend хранения (default: `Bitcask`). Доступен также `Fixed` backend.

Все данные хранятся как `[u8; V]` внутри ConstTree. ZeroTree добавляет
типизированный API, конвертируя через `IntoBytes::as_bytes()` и
`FromBytes::read_from_bytes()`.

### Выбор backend

```rust,ignore
// Bitcask (default) — append-only log + compaction
let tree = ZeroTree::<MyKey, 16, Counters>::open(path, Config::balanced().build())?;

// FixedStore — fixed-slot pwrite, без compaction, предсказуемая latency
let tree = ZeroTree::<MyKey, 16, Fixed, Counters>::open(path, FixedConfig::balanced().build())?;
```

FixedStore оптимален для частых обновлений (счётчики, метрики, сессии). Подробнее — `comparison.md`, секция "Bitcask store vs FixedStore".

Compile-time assertion: `const { assert!(size_of::<T>() == V) }`.

## Trait bounds

`T: FromBytes + IntoBytes + Immutable + KnownLayout`

Все эти traits derive-able через `#[derive(FromBytes, IntoBytes, Immutable, KnownLayout)]`.
Тип должен быть `#[repr(C)]` или `#[repr(transparent)]`.

## API

```rust,ignore
use zerocopy::{FromBytes, IntoBytes, Immutable, KnownLayout};

#[derive(FromBytes, IntoBytes, Immutable, KnownLayout, Clone, Copy, Debug)]
#[repr(C)]
struct Counters {
    views: u64,
    likes: u64,
}

let tree = ZeroTree::<16, { size_of::<Counters>() }, Counters>::open(
    "data/counters",
    Config::balanced().build(),
)?;

tree.put(&key, &Counters { views: 1, likes: 0 })?;

if let Some(c) = tree.get(&key) {
    println!("views: {}", c.views);
}

// Iteration: Item = ([u8; K], T)
for (key, counters) in tree.iter() { }

// DoubleEndedIterator
let top = tree.prefix_iter(&prefix).rev().take(10);

tree.close()?;
```

## Сравнение с TypedTree

| | ZeroTree | TypedTree |
|-|----------|-----------|
| Основа | ConstTree wrapper | собственный SkipList node |
| Codec | не нужен (zerocopy) | Codec<T> (rapira, bitcode, custom) |
| Типы | `#[repr(C)]`, fixed layout | любой `T: Send + Sync` |
| Heap fields | нет (String, Vec и т.д.) | да |
| Overhead | zero (transmute) | encode/decode на write/recovery |
| Feature flag | нет (zerocopy — core dep) | `typed-tree` |
| put() принимает | `&T` (reference) | `T` (ownership) |
| get() возвращает | `T` (copy) | `TypedRef<T>` (guard-protected ref) |
| Clone | не нужен | только `compact()` |

## Когда что использовать

- **Fixed layout, no heap** (counters, coordinates, packed structs) → `ZeroTree`
- **Complex types** (String, Vec, enums with data) → `TypedTree`
- **Raw bytes** → `ConstTree` напрямую
