Skip to content

lieldulev/RustStableIndexVector

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rust Port of Stable Index Vector

A Rust port of pezzzaswork's Stable Index Vector C++ library. This library provides a vector container with stable IDs for accessing elements, even after insertions and deletions.

Watch original YouTube video here.

Features

  • Stable IDs: Objects are accessed via IDs that remain valid regardless of other insertions/deletions.
  • Handle System: Smart handle objects that can detect if their referenced object has been erased.
  • Cache-Friendly: Data stored contiguously in a Vec<T> for efficient iteration.

Installation

Add this to your Cargo.toml (if published) or use it as a library module:

[dependencies]
rust_stable_index_vector = { path = "." }

Quick Start

Basic Usage

use rust_stable_index_vector::IndexVector;

struct Entity {
    x: i32,
    y: i32,
    name: String,
}

fn main() {
    let mut entities = IndexVector::new();
    
    // Add objects - returns a stable ID
    let player_id = entities.push(Entity { x: 0, y: 0, name: "Player".to_string() });
    let enemy_id = entities.push(Entity { x: 10, y: 5, name: "Enemy".to_string() });
    
    // Access via ID (panics if invalid, use get() for checking)
    entities[player_id].x = 5;
    
    // Erase objects - other IDs remain valid
    entities.remove(enemy_id);
    
    // player ID still works!
    println!("{}", entities[player_id].name);
}

Using Handles

Handles are smart references that know when their object has been deleted.

use rust_stable_index_vector::IndexVector;

fn main() {
    let mut entities = IndexVector::new();
    let id = entities.push(100);

    // Create a handle
    let handle = entities.create_handle(id);

    // Check validity
    if handle.is_valid(&entities) {
        if let Some(val) = handle.get(&entities) {
             println!("Value: {}", val);
        }
    }

    // After erasing, handle becomes invalid
    entities.remove(id);
    
    // Handle is now invalid
    if !handle.is_valid(&entities) {
        println!("Object was deleted!");
    }
}

Iteration

Iterate directly over the contiguous data:

// Iterate over references
for entity in &entities {
    println!("{}", entity.name);
}

// Iterate over mutable references
for entity in &mut entities {
    entity.x += 1;
}

Conditional Removal

Since IndexVector relies on stable IDs, standard retain might be tricky if we want to preserve generic iteration, but we can do:

// Collect IDs to remove
let ids_to_remove: Vec<_> = entities.iter().enumerate() // Note: iter gives &T, not ID
    .zip(0..entities.len()) // This is tricky because iteration is dense data, not IDs.
    // IndexVector iteration doesn't easily expose IDs matching data.
    // For now, simple removal by known ID is recommended.
    .collect();

API Reference

IndexVector<T>

Method Description
push(obj) Move object into vector, returns ID
remove(id) Remove object by ID
get(id) Access object by ID (Option<&T>)
get_mut(id) Access mutable object by ID (Option<&mut T>)
len() / is_empty() Container size queries
create_handle(id) Create a validity-tracking handle
is_valid(id, validity_id) Check if ID is still valid
reserve(n) Pre-allocate memory
clear() Remove all objects

Handle

Method Description
get(vector) Access underlying object (Option<&T>)
is_valid(vector) Check if referenced object still exists
id() Get the associated ID

How It Works

  • Objects are stored contiguously in a data Vec.
  • An index Vec maps stable IDs to current data positions.
  • On deletion, the swap_remove strategy is used: the last element is swapped into the gap, and the map is updated.
  • Validity IDs in metadata detect use-after-erase scenarios (ABA problem prevention).

License

[MIT / Apache 2.0]

About

A Rust port of pezzzaswork's Stable Index Vector

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages