| Crates.io | memmap3 |
| lib.rs | memmap3 |
| version | 0.1.0 |
| created_at | 2025-09-27 20:57:51.707557+00 |
| updated_at | 2025-09-27 20:57:51.707557+00 |
| description | Safe, zero-copy memory-mapped I/O. Drop-in replacement for memmap2 with persistent structs and zero unsafe in user code. |
| homepage | |
| repository | https://gitlab.com/deepbrainspace/memmap3 |
| max_upload_size | |
| id | 1857686 |
| size | 431,939 |
Safe memory-mapped I/O with zero-copy persistent data structures.
memmap3 is a complete drop-in replacement for memmap2 that adds a huge additional list of 'safe' features. All memmap2 functionality is available, plus powerful new APIs that eliminate unsafe code while providing automatic persistence.
<< for intuitive data manipulationAdd to your Cargo.toml:
[dependencies]
memmap3 = "0.1"
Create persistent data structures:
use memmap3::prelude::*;
#[mmap_struct]
struct Counter {
#[mmap(atomic)]
value: u64,
name: [u8; 32],
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create persistent data
let mut counter = MmapStruct::<Counter>::create("/tmp/counter.mmap")?;
&mut counter.name << "my_counter";
// Atomic operations work across processes
let old_value = counter.value.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
println!("Counter: {} -> {}", old_value, old_value + 1);
Ok(())
}
#[mmap_struct] macro// Just change your import:
use memmap2::{Mmap, MmapOptions}; // From this
use memmap3::{Mmap, MmapOptions}; // To this
// All existing memmap2 code works unchanged!
Transform regular Rust structs into persistent, memory-mapped types:
use memmap3::prelude::*;
#[mmap_struct]
struct MyData {
// Regular fields (primitives, enums)
id: u64,
active: bool,
// Atomic fields (thread-safe across processes)
#[mmap(atomic)]
counter: u64,
// Auto-detected strings (default for [u8; N])
name: [u8; 32],
// Explicit raw binary data
#[mmap(raw)]
key: [u8; 32],
// Fixed-capacity vectors
#[mmap(vec)]
scores: [u32; 10],
// String arrays
#[mmap(string_array)]
tags: [[u8; 16]; 5],
// Unlimited growth storage
#[mmap(segmented)]
events: [u64; 0],
}
Smooth, intuitive syntax for common operations:
// String assignment
&mut my_string << "Hello";
// Vector append
&mut my_vec << item;
// HashMap insertion
&mut my_map << ("key", "value");
// HashMap key assignment using macro
hashmap_index!(my_map["key"] << "value");
// Segmented append
&mut my_segmented << item;
#[repr(C)]#[mmap(atomic)])Transform any primitive to thread-safe atomic:
u64 → MmapAtomicU64 (fetch_add, compare_exchange, etc.)bool → MmapAtomicBool (load, store, etc.)[u8; N] → MmapString<N> (default behavior)#[mmap(string)] to force string behavior#[mmap(raw)] to keep as byte array#[mmap(vec)] transforms [T; N] → MmapVec<T, N>#[mmap(string_array)] transforms [[u8; LEN]; N] → MmapStringArray<N, LEN>MmapHashMap<K, V> for key-value storage#[mmap(segmented)] for unlimited growth (breaks fixed-size constraint)[[[u8; X]; Y]; Z] for N-dimensional dataSerialize/Deserialize typeCreate sophisticated data structures for complex queries:
use memmap3::prelude::*;
#[mmap_struct]
struct BitIndex {
// 3D lookup table for fast joins
index: [[[u8; 256]; 256]; 256],
// User data indexed by multiple dimensions
users_by_age_location: [[u64; 100]; 50], // [age][location] → user_id
// Unlimited growth using segmented
#[mmap(segmented)]
overflow_data: [u64; 0],
}
#[mmap(segmented)] allows unlimited growthSafe wrapper for memory-mapped structs with automatic file management:
use memmap3::prelude::*;
#[mmap_struct]
struct GameState {
level: u32,
score: u64,
player_name: [u8; 32],
}
let mut game = MmapStruct::<GameState>::create("game.mmap")?;
game.level = 5;
game.score = 12345;
&mut game.player_name << "Player1";
Thread-safe operations across processes:
use memmap3::prelude::*;
#[mmap_struct]
struct Metrics {
#[mmap(atomic)]
requests: u64,
#[mmap(atomic)]
errors: u64,
}
let metrics = MmapStruct::<Metrics>::create("metrics.mmap")?;
metrics.requests.fetch_add(1, Ordering::SeqCst);
Persistent data structures with dynamic sizing:
use memmap3::prelude::*;
// Persistent hash map
let mut cache = MmapHashMap::<&str, &str>::create("cache.mmap")?;
cache.insert("key1", "value1")?;
// Multiple assignment syntaxes available:
&mut cache << ("key2", "value2"); // Tuple insertion
hashmap_index!(cache["key3"] << "value3"); // Index-style assignment
cache.set("key4", "value4")?; // Direct set method
// Persistent vector
let mut log = MmapVec::<u64, 1000>::new();
log.push(1234567890); // timestamp
// Persistent string
let mut name = MmapString::<64>::new();
&mut name << "Alice";
#[repr(C)]#[mmap(atomic)])Transforms regular types to atomic equivalents for thread-safe access:
u8 → MmapAtomicU8, u16 → MmapAtomicU16, etc.bool → MmapAtomicBool#[mmap(string)])Transforms byte arrays to UTF-8 strings with helper methods:
[u8; N] → MmapString<N>.set(), << operator, .as_str(), .clear()#[mmap(vec)])Transforms arrays to fixed-capacity vectors:
[T; N] → MmapVec<T, N>.push(), .pop(), .len(), .iter(), indexing#[mmap(string_array)])Transforms 2D byte arrays to arrays of strings:
[[u8; LEN]; N] → MmapStringArray<N, LEN>See the examples/ directory for complete working examples:
cargo run --example 01-002_macro_usage
cargo run --example 03-001_atomic_operations
cargo run --example 02-002_string_operations
cargo run --example 04-003_event_log
cargo run --example 14_hashmap
use memmap3::prelude::*;
#[mmap_struct]
struct Config {
max_connections: u32,
timeout_ms: u32,
debug_mode: bool,
server_name: [u8; 64],
}
let mut config = MmapStruct::<Config>::create("app.config")?;
config.max_connections = 1000;
config.timeout_ms = 5000;
&mut config.server_name << "production-server";
// Configuration persists across application restarts
use memmap3::prelude::*;
use std::sync::atomic::Ordering;
#[mmap_struct]
struct SharedData {
#[mmap(atomic)]
message_count: u64,
#[mmap(atomic)]
worker_status: u32,
shared_buffer: [u8; 1024],
}
// Process A
let shared = MmapStruct::<SharedData>::create("/tmp/ipc.mmap")?;
shared.message_count.store(42, Ordering::SeqCst);
// Process B can read the same data
let shared = MmapStruct::<SharedData>::open("/tmp/ipc.mmap")?;
let count = shared.message_count.load(Ordering::SeqCst);
println!("Messages: {}", count); // Prints: Messages: 42
use memmap3::prelude::*;
use std::sync::atomic::Ordering;
#[mmap_struct]
struct Analytics {
#[mmap(atomic)]
page_views: u64,
#[mmap(atomic)]
unique_visitors: u64,
#[mmap(atomic)]
conversion_rate: u64, // Fixed-point arithmetic
}
let analytics = MmapStruct::<Analytics>::create("analytics.mmap")?;
// Record events
analytics.page_views.fetch_add(1, Ordering::SeqCst);
analytics.unique_visitors.fetch_add(1, Ordering::SeqCst);
// Calculate conversion rate (example: 2.5% as 250 basis points)
let rate = (conversions * 10000) / page_views;
analytics.conversion_rate.store(rate, Ordering::SeqCst);
The #[mmap_struct] attribute macro:
#[repr(C)] for predictable memory layoutYou can wrap MmapStruct in Arc for safe sharing across threads:
use memmap3::prelude::*;
use std::sync::Arc;
use std::sync::atomic::Ordering;
#[mmap_struct]
struct Config {
port: u16,
#[mmap(atomic)]
counter: u64,
}
// Single-threaded use
let mut data = MmapStruct::<Config>::create("config.mmap")?;
data.port = 8080; // Can modify all fields
// Multi-threaded use with Arc
let shared = Arc::new(MmapStruct::<Config>::create("config.mmap")?);
// Clone for each thread
let thread_data = shared.clone();
std::thread::spawn(move || {
// Atomic fields can be modified safely
thread_data.counter.fetch_add(1, Ordering::Relaxed);
// Regular fields are read-only when shared via Arc
println!("Port: {}", thread_data.port);
});
Access Patterns:
Automatic string operations for byte arrays:
use memmap3::prelude::*;
#[mmap_struct]
struct User {
id: u64,
name: [u8; 32], // Automatically treated as string
email: [u8; 128], // Automatically treated as string
}
let mut user = MmapStruct::<User>::create("user.mmap")?;
user.id = 12345;
// Write strings using << operator
&mut user.name << "Alice Smith";
&mut user.email << "alice@example.com";
// Read strings back
println!("User: {} ({})", user.name.as_str(), user.email.as_str());
Enable additional functionality:
[dependencies]
memmap3 = { version = "0.1", features = ["serde"] }
serde - Serialize/deserialize support for complex typesmemmap3 provides zero-copy access with minimal overhead:
Multiple layers of safety validation:
#[mmap_struct] macro checksThis project is licensed under the MIT OR Apache-2.0 license.
Contributions are welcome! Please see our GitHub repository for guidelines.