# 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).
## Архитектура
```
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
// Bitcask (default) — append-only log + compaction
let tree = ZeroTree::<MyKey, 16, Counters>::open(path, Config::default())?;
// FixedStore — fixed-slot pwrite, без compaction, предсказуемая latency
let tree = ZeroTree::<MyKey, 16, Fixed, Counters>::open(path, FixedConfig::default())?;
```
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
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(
Config::new("data/counters"),
)?;
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
| Основа | 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` напрямую