use std::alloc::{Layout, alloc};
use hashmap_mem::{
MapHeader, get_or_reserve_entry, init, layout, lookup, overwrite, remove, reserve_entry,
};
#[test]
fn test_basic_insert_lookup() {
let key_size = 4;
let value_size = 8;
let (_, map_init) = layout(key_size, 4, value_size, 8, 16);
let layout = Layout::from_size_align(map_init.total_size as usize, 8).unwrap();
let map_base = unsafe { alloc(layout) };
assert!(!map_base.is_null());
unsafe {
init(map_base, &map_init);
let key: u32 = 0x12345678;
let key_ptr = (&raw const key).cast::<u8>();
let value_ptr = get_or_reserve_entry(map_base, key_ptr);
assert!(!value_ptr.is_null());
*value_ptr.cast::<u64>() = 0xABCDEF0123456789;
let header = &*(map_base as *const MapHeader);
assert_eq!(header.element_count, 1);
let found_ptr = lookup(map_base, key_ptr);
assert!(!found_ptr.is_null());
assert_eq!(*(found_ptr as *const u64), 0xABCDEF0123456789);
}
}
#[test]
fn test_remove() {
let key_size = 2;
let value_size = 4;
let (_, map_init) = layout(key_size, 2, value_size, 4, 8);
let layout = Layout::from_size_align(map_init.total_size as usize, 8).unwrap();
let map_base = unsafe { alloc(layout) };
assert!(!map_base.is_null());
unsafe {
init(map_base, &map_init);
let key1: u16 = 100;
let key2: u16 = 200;
let key1_ptr = (&raw const key1).cast::<u8>();
let key2_ptr = (&raw const key2).cast::<u8>();
let value1_ptr = get_or_reserve_entry(map_base, key1_ptr);
*value1_ptr.cast::<u32>() = 1000;
let value2_ptr = get_or_reserve_entry(map_base, key2_ptr);
*value2_ptr.cast::<u32>() = 2000;
let header = &*(map_base as *const MapHeader);
assert_eq!(header.element_count, 2);
let removed = remove(map_base, key1_ptr);
assert!(removed);
let header = &*(map_base as *const MapHeader);
assert_eq!(header.element_count, 1);
let found_ptr = lookup(map_base, key1_ptr);
assert!(found_ptr.is_null());
let found_ptr = lookup(map_base, key2_ptr);
assert!(!found_ptr.is_null());
assert_eq!(*(found_ptr as *const u32), 2000);
}
}
#[test]
fn test_overwrite() {
let key_size = 4;
let value_size = 4;
let (_, source_init) = layout(key_size, 4, value_size, 4, 8);
let (_, target_init) = layout(key_size, 4, value_size, 4, 16);
let source_layout = Layout::from_size_align(source_init.total_size as usize, 8).unwrap();
let source_base = unsafe { alloc(source_layout) };
assert!(!source_base.is_null());
let target_layout = Layout::from_size_align(target_init.total_size as usize, 8).unwrap();
let target_base = unsafe { alloc(target_layout) };
assert!(!target_base.is_null());
unsafe {
init(source_base, &source_init);
init(target_base, &target_init);
for i in 0..3 {
let key = i;
let key_ptr = (&raw const key).cast::<u8>();
let value_ptr = get_or_reserve_entry(source_base, key_ptr);
*value_ptr.cast::<i32>() = i * 100;
}
let source_header = &*(source_base as *const MapHeader);
assert_eq!(source_header.element_count, 3);
let success = overwrite(target_base, source_base);
assert!(success);
let target_header = &*(target_base as *const MapHeader);
assert_eq!(target_header.element_count, 3);
for i in 0..3 {
let key = i;
let key_ptr = (&raw const key).cast::<u8>();
let found_ptr = lookup(target_base, key_ptr);
assert!(!found_ptr.is_null());
assert_eq!(*(found_ptr as *const i32), i * 100);
}
}
}
#[test]
fn test_reserve_entry() {
let key_size = 4;
let value_size = 8;
let (_, map_init) = layout(key_size, 4, value_size, 8, 16);
let layout = Layout::from_size_align(map_init.total_size as usize, 8).unwrap();
let map_base = unsafe { alloc(layout) };
assert!(!map_base.is_null());
unsafe {
init(map_base, &map_init);
let key: u32 = 0x42424242;
let key_ptr = (&raw const key).cast::<u8>();
let value_ptr = reserve_entry(map_base, key_ptr);
assert!(!value_ptr.is_null());
*value_ptr.cast::<u64>() = 0xDEADBEEF;
let header = &*(map_base as *const MapHeader);
assert_eq!(header.element_count, 1);
let found_ptr = lookup(map_base, key_ptr);
assert!(!found_ptr.is_null());
assert_eq!(*(found_ptr as *const u64), 0xDEADBEEF);
}
}
#[test]
#[should_panic(expected = "Key already exists in map")]
fn test_reserve_entry_panics_on_duplicate() {
let key_size = 4;
let value_size = 8;
let (_, map_init) = layout(key_size, 4, value_size, 8, 16);
let layout = Layout::from_size_align(map_init.total_size as usize, 8).unwrap();
let map_base = unsafe { alloc(layout) };
assert!(!map_base.is_null());
unsafe {
init(map_base, &map_init);
let key: u32 = 0x99999999;
let key_ptr = (&raw const key).cast::<u8>();
let value_ptr = reserve_entry(map_base, key_ptr);
assert!(!value_ptr.is_null());
*value_ptr.cast::<u64>() = 0x1111;
reserve_entry(map_base, key_ptr);
}
}