spatial_hash_3d 0.1.6

3D spatial hash grid implementation optimized for speed. What it does/why you'd want one: https://www.youtube.com/watch?v=sx4IIQL0x7c
Documentation
use cgmath::Vector3;
use criterion::{criterion_group, criterion_main, Criterion};
use rand::rngs::SmallRng;
use rand::{Rng, SeedableRng};
use spatial_hash_3d::*;
use std::hint::black_box;

#[derive(Debug)]
pub struct Data {
    some_data: u32,
}

impl Default for Data {
    fn default() -> Self {
        Data { some_data: 0 }
    }
}

fn create_and_fill(x: u32, y: u32, z: u32) -> SpatialHashGrid<Data> {
    let mut sh: SpatialHashGrid<Data> =
        SpatialHashGrid::new(x as usize, y as usize, z as usize, Data::default);
    let mut count = 0;
    for (i, j, k) in itertools::iproduct!(0..x, 0..y, 0..z) {
        let pos = Vector3::new(i, j, k);
        sh[pos] = Data { some_data: count };
        count += 1;
    }
    sh
}

/// Creates random bounding boxes within x,y,z size
fn generate_bounding_box(
    rng: &mut SmallRng,
    x: u32,
    y: u32,
    z: u32,
) -> (Vector3<u32>, Vector3<u32>) {
    let min = Vector3::new(
        rng.random_range(0..(x - 2)),
        rng.random_range(0..(y - 2)),
        rng.random_range(0..(z - 2)),
    );
    let max = Vector3::new(
        rng.random_range(min.x..x),
        rng.random_range(min.y..y),
        rng.random_range(min.z..z),
    );
    if min.x > max.x || min.y > max.y || min.z > max.z {
        panic!("Generated volume is not in this Universe");
    }
    (min, max)
}

fn bench_get_filled_data(sh: &SpatialHashGrid<Data>, min: Vector3<u32>, max: Vector3<u32>) {
    for (c, elem) in sh.iter_cubes(min, max) {
        black_box(c);
        black_box(elem);
    }
}

fn bench_modify_filled_data(sh: &mut SpatialHashGrid<Data>, min: Vector3<u32>, max: Vector3<u32>) {
    for (c, idx, elem) in sh.iter_cubes_mut(min, max) {
        elem.some_data += c.x;
        black_box(idx);
    }
}

/// Measures how quickly the data is retrieved from the structure
/// Two tests inside - one for mutable and one for immutable iteration
pub fn bench_get_data_if_there(c: &mut Criterion) {
    let mut rng = SmallRng::seed_from_u64(42);

    let mut group = c.benchmark_group("lookups");

    for size in [5u32, 10, 20] {
        group.bench_with_input(
            criterion::BenchmarkId::from_parameter(size),
            &size,
            |b, &size| {
                //generate max border values for the base volume, Max value for each axis is never larger than 20
                let (x, y, z) = (size, size, size);
                //generate bounding volume based on the previous values, each value is never larger than "max border values"

                //fill general space
                let spatial = create_and_fill(x, y, z);

                b.iter(|| {
                    let (min, max) = generate_bounding_box(&mut rng, x, y, z);
                    //bounding box is located in general space, look for the data in bounding box
                    bench_get_filled_data(&spatial, min, max);
                })
            },
        );
    }
    drop(group);
    let mut group = c.benchmark_group("edits");

    for size in [5u32, 10, 20] {
        group.bench_with_input(
            criterion::BenchmarkId::from_parameter(size),
            &size,
            |b, &size| {
                //generate max border values for the base volume, Max value for each axis is never larger than 20
                let (x, y, z) = (size, size, size);
                //generate bounding volume based on the previous values, each value is never larger than "max border values"

                //fill general space
                let mut spatial = create_and_fill(x, y, z);

                // println!("General space {:?}, {:?}, {:?}", x, y, z);
                // println!("Min={:?}, Max={:?}", min, max);

                b.iter(|| {
                    let (min, max) = generate_bounding_box(&mut rng, x, y, z);
                    //bounding box is located in general space, look for the data in bounding box
                    bench_modify_filled_data(&mut spatial, min, max);
                    black_box(&spatial);
                })
            },
        );
    }
}

/// Measures how quickly the data is filled in the structure
/// Should be pretty fast if size of D is small

pub fn bench_fill_data(c: &mut Criterion) {
    let mut group = c.benchmark_group("writes");
    for size in [5u32, 10, 20] {
        group.bench_with_input(
            criterion::BenchmarkId::from_parameter(size),
            &size,
            |b, &size| {
                b.iter(|| {
                    let spatial = create_and_fill(size, size, size);
                    black_box(spatial);
                })
            },
        );
    }
}

criterion_group!(benches, bench_get_data_if_there, bench_fill_data);
criterion_main!(benches);