Expand description
§nearest
Self-relative pointers and region-based allocation for Rust.
nearest stores entire data graphs in a single contiguous byte buffer where
all internal pointers are 4-byte i32 offsets relative to their own address.
This makes Clone a plain memcpy — no pointer fixup needed.
Mutations use a branded Session API (ghost-cell pattern) where Ref
tokens carry a compile-time brand preventing cross-session use or escape —
all at zero runtime cost.
§Core types
| Type | Size | Role |
|---|---|---|
Region<T> | heap | Owning contiguous buffer; root T at byte 0 |
Near<T> | 4 B | Self-relative pointer (NonZero<i32> offset) |
NearList<T> | 8 B | Segmented linked list (offset + length) |
Session | — | Branded mutable session for safe mutation |
Ref | 4 B | Branded position token (Copy, no borrow) |
Flat | — | Marker trait: no Drop, no heap pointers |
Emit | — | Builder trait for declarative construction |
§Defining types
#[derive(Flat)] generates both the Flat safety marker
and the Emit builder, including a make() factory for each struct or
enum variant.
§Structs
use nearest::{Flat, Near, NearList};
#[derive(Flat, Debug)]
struct Func {
name: u32,
entry: Near<Block>,
}
#[derive(Flat, Debug)]
struct Block {
id: u32,
insts: NearList<u32>,
}Fields may be primitives (u8–u64, i32–i64, bool), Near<T>,
NearList<T>, Option<Near<T>>, or any other Flat type.
§Enums
Enums require #[repr(C, u8)] (or #[repr(u8)] for unit-only enums):
use nearest::Flat;
#[derive(Flat, Copy, Clone, Debug, PartialEq)]
#[repr(C, u8)]
enum Value {
Int(u32),
Bool(bool),
}Each data variant gets a make_<variant>() factory. Unit variants need
no factory.
§Constructing a region
Region::new takes any Emit<T> builder — typically the make()
factory generated by #[derive(Flat)]. Builder arguments
correspond to fields in declaration order. Near<T> fields accept any
impl Emit<T> (usually a nested make()), and NearList<T> fields
accept any IntoIterator whose items implement Emit:
use nearest::{Flat, Near, NearList, Region, empty};
let region = Region::new(Func::make(
1, // name: u32
Block::make(0, [10u32, 20, 30]), // entry: Near<Block>
));
assert_eq!(region.name, 1);
assert_eq!(region.entry.insts.len(), 3);Use empty() for empty NearList fields:
let region = Region::new(Block::make(0, empty()));
assert!(region.insts.is_empty());§Reading data
Region<T> implements Deref<Target = T>, giving
direct access to the root value. Near<T> also dereferences to &T:
// Region<T>: Deref<Target = T>
assert_eq!(region.name, 1);
// Near<T>: Deref<Target = T>
let block: &Block = ®ion.entry;
assert_eq!(block.id, 0);
// NearList<T>: indexing and iteration
assert_eq!(block.insts[0], 10);
let sum: u32 = block.insts.iter().sum();
assert_eq!(sum, 60);§Mutating with sessions
Region::session opens a branded closure where mutations are performed
through Ref position tokens. The ghost-cell pattern guarantees refs
cannot escape the closure or be used across sessions — enforced at
compile time with zero runtime cost.
#[derive(Flat, Debug)]
struct Block {
id: u32,
items: NearList<u32>,
}
let mut region = Region::new(Block::make(1, [10u32, 20, 30]));
region.session(|s| {
// Navigate to a field, then overwrite it
let id = s.nav(s.root(), |b| &b.id);
s.set(id, 42);
// Replace an entire list
let items = s.nav(s.root(), |b| &b.items);
s.splice_list(items, [100u32, 200]);
});
assert_eq!(region.id, 42);
assert_eq!(region.items.len(), 2);
assert_eq!(region.items[0], 100);§Navigation
| Method | Purpose |
|---|---|
Session::root | Ref to the root value |
Session::nav | Navigate to a sub-field |
Session::follow | Dereference a Near<T> ref |
Session::at | Read the value at a ref |
§Scalar mutation
| Method | Purpose |
|---|---|
Session::set | Overwrite a Copy field in place |
Session::write | Overwrite with an Emit builder |
§Pointer and list replacement
| Method | Purpose |
|---|---|
Session::splice | Replace the target of a Near<T> |
Session::splice_list | Replace the contents of a NearList<T> |
§List operations
| Method | Purpose |
|---|---|
Session::push_front | Prepend one element (O(1)) |
Session::push_back | Append with cached ListTail (O(1)) |
Session::extend_list | Append multiple elements |
Session::filter_list | Keep elements matching a predicate |
Session::map_list | Transform Copy elements in place |
Session::reverse_list | Reverse element order |
Session::sort_list | Sort elements by comparator |
Session::dedup_list | Remove consecutive duplicates |
§Cursor API
For deeply nested navigation, Session::cursor provides a chainable
interface:
region.session(|s| {
s.cursor()
.at(|f| &f.entry)
.follow()
.at(|b| &b.id)
.set(99);
});
assert_eq!(region.entry.id, 99);§Serialization
Region::as_bytes returns the raw buffer contents as a &[u8], suitable
for writing to a file or sending over the network. Region::from_bytes
copies the bytes into an aligned buffer, then runs Flat::validate to
check bounds, alignment, pointer validity, and type-specific invariants
(e.g. enum discriminants, bool values) before reconstructing the region.
#[derive(Flat, Debug)]
struct Node {
id: u32,
children: NearList<u32>,
}
let original = Region::new(Node::make(1, [10u32, 20, 30]));
let bytes = original.as_bytes();
// bytes can be persisted to disk, sent over the network, etc.
let restored: Region<Node> = Region::from_bytes(bytes).unwrap();
assert_eq!(restored.id, 1);
assert_eq!(restored.children.len(), 3);Invalid or corrupted data is rejected with a ValidateError:
use nearest::{Flat, Near, Region, ValidateError};
#[derive(Flat, Debug)]
struct Flags {
active: bool,
label: Near<u32>,
}
let region = Region::new(Flags::make(true, 42u32));
let mut bytes = region.as_bytes().to_vec();
bytes[core::mem::offset_of!(Flags, active)] = 2; // corrupt the bool
assert!(Region::<Flags>::from_bytes(&bytes).is_err());§Compaction
Mutations are append-only — replaced data becomes dead bytes in the
buffer. Region::trim deep-copies only reachable data into a fresh
buffer, reclaiming the waste:
let mut region = Region::new(Block::make(1, [10u32, 20, 30]));
let before = region.byte_len();
region.session(|s| {
let items = s.nav(s.root(), |b| &b.items);
s.splice_list(items, [100u32]);
});
assert!(region.byte_len() > before);
region.trim();
assert!(region.byte_len() <= before);
assert_eq!(region.items[0], 100);After trimming, every NearList is compacted to a single contiguous
segment, making indexing O(1).
§Cloning
Self-relative offsets are position-independent, so Clone for
Region<T> is a byte-for-byte buffer copy — no pointer fixup or
graph traversal:
let region = Region::new(Block::make(1, [10u32, 20, 30]));
let cloned = region.clone();
assert_eq!(cloned.id, region.id);
assert_eq!(cloned.items[0], region.items[0]);§Features
| Feature | Default | Enables |
|---|---|---|
alloc | yes | Heap-backed AlignedBuf, Region::new, Region::trim, growable sessions |
std | no | Implies alloc; reserved for future std-only APIs |
serde | no | Serialize / Deserialize for Region<T> |
§no_std support
nearest is #![no_std] by default. Disabling the alloc feature
removes all heap allocation — use FixedBuf<N> for stack-backed
regions with a compile-time capacity:
[dependencies]
nearest = { version = "0.2", default-features = false }use nearest::{Flat, NearList, Region, FixedBuf, empty};
#[derive(Flat, Debug)]
struct Msg {
id: u32,
tags: NearList<u32>,
}
// 128-byte inline buffer, no heap allocation.
let region: Region<Msg, FixedBuf<128>> =
Region::new_in(Msg::make(1, [10u32, 20]));
assert_eq!(region.id, 1);
assert_eq!(region.tags.len(), 2);§serde
With the serde feature, Region<T> implements Serialize and
Deserialize. The region is serialized as its raw byte buffer (via
as_bytes), and deserialization runs
from_bytes validation automatically.
[dependencies]
nearest = { version = "0.2", features = ["serde"] }§Safety model
nearest is an unsafe-heavy crate. This section documents the
invariants that make the safe public API sound.
§Flat invariants
Every type stored in a region must implement Flat, which guarantees:
- No
Drop: Aconstassertion rejects types with destructors at compile time. - No heap pointers: All indirection uses
Near<T>orNearList<T>(self-relative offsets), neverBox,Vec, or raw pointers. - Correct
deep_copy: The deriveddeep_copycopies fields and patches self-relative offsets to their new positions.
§Provenance
Self-relative pointers cannot use strict Rust provenance: &self.offset
has provenance over only 4 bytes, but the target T may be larger.
Instead, every buffer allocation exposes its provenance via
expose_provenance, and reads recover it via with_exposed_provenance.
This is the canonical pattern for self-relative pointers in Rust,
validated by Miri.
§Aliasing
Mutation through Session uses pre-reservation to prevent buffer
reallocation, then recovers provenance for reads so the &T is not
derived from the &mut Region — avoiding Stacked Borrows violations.
§Branding
Region::session uses the ghost-cell pattern
(for<'id> FnOnce(&mut Session<'id, …>)) to make Ref tokens
invariant in their brand lifetime 'id. This prevents refs from
escaping the session closure or being mixed across sessions — enforced
by compile-fail tests.
§Alignment
The buffer base is aligned to max(align_of::<Root>(), 8). Every
allocation within the buffer is aligned to align_of::<T>() via
padding, with a compile-time assertion that no type exceeds the
buffer alignment.
§No-drop
The derive macro emits const { assert!(!needs_drop::<T>()) } for
every derived type, rejecting Drop impls at compile time. This
guarantees regions can be memcpy’d without running destructors.
§Minimum Supported Rust Version
This crate requires nightly Rust (pinned to nightly-2026-02-10)
due to offset_of_enum.
Re-exports§
Modules§
- session
- Branded session API for safe region mutation.
Structs§
- Aligned
Buf - Growable byte buffer with base pointer aligned to
max(align_of::<T>(), 8). - Fixed
Buf - Stack-backed fixed-capacity buffer with 8-byte alignment.
- Near
- A self-relative pointer stored as a 4-byte
NonZero<i32>offset. - Near
List - A linked list of
Tvalues stored in aRegion. - Near
List Iter - Iterator over the elements of a
NearList. - Region
- An owning, contiguous byte buffer whose root value
Tstarts at byte 0.
Enums§
- Validate
Error - Error returned by
Flat::validateandRegion::from_bytes.
Traits§
- Buf
- Backing storage for a
Region. - Emit
- Builder trait for constructing values in a
Region. - Flat
- Marker trait for types that can be stored in a
Region.
Functions§
- empty
- Returns an empty iterator suitable for any
NearList<T>emitter parameter.