deadlock 0.10.0

Thread-safe slot map and slot min-heap with stable RAII handle
Documentation
use deadlock::{
    SlotMap, SlotMapId, SlotMapIter, SlotMapIterMut, SlotMapRef, SlotMapRefMut, SlotMapShardRef,
};
use std::{
    iter,
    sync::{Arc, Mutex},
    thread,
};

fn _slotmap_send_sync_checks<'a>() {
    fn assert_send_sync<T: Send + Sync>() {}

    assert_send_sync::<SlotMap<i32>>();
    assert_send_sync::<SlotMapId<i32>>();
    assert_send_sync::<SlotMapRef<'a, i32>>();
    assert_send_sync::<SlotMapRefMut<'a, i32>>();
    assert_send_sync::<SlotMapShardRef<'a, i32>>();
    assert_send_sync::<SlotMapIter<'a, i32>>();
    assert_send_sync::<SlotMapIterMut<'a, i32>>()
}

#[test]
fn shards_iter_yields_all_entries() {
    let map = SlotMap::new();
    let n = 64_i32;
    let _ids = (0..n).map(|i| map.insert(i * 5)).collect::<Vec<_>>();

    let mut collected = map
        .shards()
        .flat_map(|shard| shard.iter().copied().collect::<Vec<_>>())
        .collect::<Vec<_>>();
    collected.sort_unstable();

    assert_eq!(collected.len(), n as usize);
    assert_eq!(collected, (0..n).map(|i| i * 5).collect::<Vec<_>>())
}

#[test]
fn shards_total_count_matches_len() {
    let map = SlotMap::new();
    let n = 48;
    let _ids = (0..n).map(|i| map.insert(i)).collect::<Vec<_>>();

    let total = map
        .shards()
        .map(|shard| shard.iter().count())
        .sum::<usize>();
    assert_eq!(total, n);
    assert_eq!(total, map.len())
}

#[test]
fn insert_get_many_preserves_values_and_len() {
    let map = SlotMap::new();
    let n = 64;
    let ids = (0..n).map(|i| map.insert(i)).collect::<Vec<_>>();

    assert_eq!(map.len(), n);

    for (i, id) in ids.iter().enumerate() {
        assert_eq!(*id.get(), i)
    }
}

#[test]
fn len_decreases_when_id_is_dropped() {
    let map = SlotMap::new();
    let n = 48;
    let mut ids = (0..n).map(|i| map.insert(i)).collect::<Vec<_>>();
    assert_eq!(map.len(), n);

    for _ in 0..(n / 2) {
        ids.pop();
    }

    assert_eq!(map.len(), n / 2);
    assert_eq!(ids.len(), n / 2);

    drop(ids);

    assert!(map.is_empty())
}

#[test]
fn into_inner_returns_value_and_removes_entry() {
    let map = SlotMap::new();
    let id = map.insert(100);
    assert_eq!(map.len(), 1);

    let v = id.into_inner();
    assert_eq!(v, 100);
    assert_eq!(map.len(), 0);
    assert!(map.is_empty())
}

#[test]
fn get_mut_modifies_value() {
    let map = SlotMap::new();
    let id = map.insert(10);
    assert_eq!(*id.get(), 10);

    *id.get_mut() = 20;
    assert_eq!(*id.get(), 20);
}

#[test]
fn slot_reuse_after_removal_keeps_correct_values() {
    let map = SlotMap::new();
    let n = 32;
    let ids = (0..n).map(|i| map.insert(i)).collect::<Vec<_>>();

    for id in ids {
        let _ = id.into_inner();
    }

    assert!(map.is_empty());

    let again = (0..n).map(|i| map.insert(i + 100)).collect::<Vec<_>>();
    assert_eq!(map.len(), n);

    for (i, id) in again.iter().enumerate() {
        assert_eq!(*id.get(), i + 100)
    }
}

#[test]
fn ref_remains_valid_after_other_id_dropped() {
    let map = SlotMap::new();
    let id0 = map.insert(42);
    let id1 = map.insert(43);
    let r0 = id0.get();
    assert_eq!(*r0, 42);

    drop(id1);
    assert_eq!(*r0, 42);
    assert_eq!(map.len(), 1)
}

#[test]
fn iter_yields_all_entries() {
    let map = SlotMap::new();
    let n = 32;
    let _ids = (0..n).map(|i| map.insert(i * 10)).collect::<Vec<_>>();

    let collected = map.iter().map(|r| *r).collect::<Vec<_>>();
    assert_eq!(collected.len(), n);

    let mut sorted = collected;
    sorted.sort_unstable();
    assert_eq!(sorted, (0..n).map(|i| i * 10).collect::<Vec<_>>())
}

#[test]
fn iter_mut_modifies_values() {
    let map = SlotMap::new();
    let _ids = (0..8).map(|i| map.insert(i)).collect::<Vec<_>>();

    for mut r in map.iter_mut() {
        *r += 100;
    }

    let collected = map.iter().map(|r| *r).collect::<Vec<_>>();
    let mut sorted = collected;
    sorted.sort_unstable();
    assert_eq!(sorted, (100..108).collect::<Vec<_>>())
}

#[test]
fn send_sync_multi_threaded_insert() {
    let map = Arc::new(SlotMap::new());
    let ids = Arc::new(Mutex::new(Vec::new()));
    let handles = (0..4)
        .map(|i| {
            let map = map.clone();
            let ids = ids.clone();

            thread::spawn(move || {
                let local_ids = (0..100)
                    .map(|j| map.insert(i * 100 + j))
                    .collect::<Vec<_>>();
                ids.lock().unwrap().extend(local_ids)
            })
        })
        .take(4)
        .collect::<Vec<_>>();

    for handle in handles {
        handle.join().unwrap()
    }

    assert_eq!(map.len(), 400)
}

#[test]
fn send_sync_multi_threaded_iter() {
    let map = Arc::new(SlotMap::new());
    let _ids = (0..100).map(|i| map.insert(i)).collect::<Vec<_>>();

    let handles = iter::repeat_with(|| {
        let map = map.clone();

        thread::spawn(move || {
            let count = map.iter().count();
            assert_eq!(count, 100)
        })
    })
    .take(4)
    .collect::<Vec<_>>();

    for handle in handles {
        handle.join().unwrap()
    }
}