1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! Flat byte-pool storage structures for plugmem.
//!
//! This crate is the storage foundation of the plugmem engine, but it is
//! deliberately generic: nothing here knows about facts, vectors or LLMs.
//! If you need a compact, allocation-frugal, `no_std` sorted container whose
//! in-memory representation *is* its serialized form, you can lift it into
//! your own project as-is — see `examples/` for self-contained walkthroughs.
//!
//! # Philosophy
//!
//! 1. **State is flat bytes.** A container is one contiguous byte pool plus a
//! few small metadata arrays. No per-element allocations, no pointers, no
//! `Box`/`Rc` graphs. Persisting a container is `memcpy`; loading it back
//! is bounds-checking the metadata and adopting the bytes.
//! 2. **Costs are local and visible.** Every operation touches one 4 KiB
//! page (one cache-friendly unit). Worst cases are small, fixed and
//! measured — the optional [`counters`](#feature-flags) feature exposes
//! deterministic work counters used as CI performance gates.
//! 3. **Keys are big-endian.** Byte-wise comparison of an encoded key must
//! equal the numeric comparison of its source value, so binary search and
//! ordered iteration work directly on raw bytes. Helpers live in [`key`].
//!
//! # The four structures
//!
//! | Structure | Shape | Typical use |
//! |---|---|---|
//! | [`Arena`] | sorted fixed-size records, sharded 4 KiB pages | primary record store, ordered indexes |
//! | [`BlobHeap`] | append-only variable-length blobs, dense ids | texts, names, raw vectors |
//! | [`ChunkPool`] | many small growable lists over 64-byte chunks | posting lists, adjacency lists |
//! | [`Interner`] | string -> dense `u32` (heap + flat hash table) | terms, tags, entity names |
//!
//! # Quick start
//!
//! ```
//! use plugmem_arena::{Arena, ArenaCfg, ShardMode, Slot, key};
//!
//! /// A tiny fixed-size record: 4-byte big-endian key + 1-byte payload.
//! #[derive(Debug, PartialEq)]
//! struct Rec {
//! id: u32,
//! level: u8,
//! }
//!
//! impl Slot for Rec {
//! const SIZE: usize = 5;
//! const KEY_LEN: usize = 4;
//! fn write(&self, out: &mut [u8]) {
//! key::write_u32(out, self.id);
//! out[4] = self.level;
//! }
//! fn read(bytes: &[u8]) -> Self {
//! Rec { id: key::read_u32(bytes), level: bytes[4] }
//! }
//! }
//!
//! let mut arena = Arena::<Rec>::new(ArenaCfg::new(64, ShardMode::Ordered)).unwrap();
//! arena.insert(&Rec { id: 7, level: 3 }).unwrap();
//! arena.insert(&Rec { id: 1, level: 9 }).unwrap();
//!
//! let mut key_buf = [0u8; 4];
//! key::write_u32(&mut key_buf, 7);
//! assert_eq!(arena.get(&key_buf), Some(Rec { id: 7, level: 3 }));
//!
//! // Ordered mode: iteration yields ascending keys across all shards.
//! let ids: Vec<u32> = arena.iter().map(|r| r.id).collect();
//! assert_eq!(ids, [1, 7]);
//! ```
//!
//! # The one `unsafe`
//!
//! The single default `unsafe` in this crate is page allocation without
//! zeroing (`Vec::reserve` + `set_len`). It is kept because it was
//! *measured*, not assumed: on the wasm target (our primary portability
//! target) zeroing freshly grown pages made the allocation path **12x
//! slower** (wasmtime, 32k pages: 3889 us zeroed vs 316 us uninit), while on
//! native x86-64 the difference is noise. The safety invariant is simple and
//! local: *bytes of a page beyond `count * Slot::SIZE` are never read* —
//! every read is bounded by the per-shard element count, and a slot is fully
//! written before `count` is incremented. See `Arena::ensure_page` for the
//! full safety comment. A consequence worth knowing: `Arena` intentionally
//! implements neither `Clone` nor `PartialEq`, because a byte-wise clone or
//! comparison would read those uninitialized tails.
//!
//! Bounds-check elimination (`get_unchecked`) was measured on the same
//! harness and rejected: <= 1% on native, *slower* under wasm (the runtime
//! bounds-checks linear memory anyway). Safe indexing everywhere else.
//!
//! # Feature flags
//!
//! - `std` *(default)* — nothing yet beyond linking `std` for consumers'
//! convenience; the crate is fully functional as `no_std + alloc`.
//! - `counters` — deterministic work counters (`Counters`) on every
//! container: key comparisons, bytes shifted, pages allocated. Zero cost
//! when disabled (the increments compile away).
extern crate alloc;
pub use ;
pub use ;
pub use ;
pub use Error;
pub use ;
pub use Slot;
pub use Counters;