Passing a Hashmap Ptr over the FFI border and back to Rust to edit the Hashmap

Hello (:

I am writing a tool in a Interpreter Language and one thing i need todo in this Tool is to load 50.000 to 2.000.000 X,Y Positions (eg. -1010,-1752) into a map, check against it and if present return me data that is saved to that X,Y. This high level language does not have suitable datatypes to do that in a resonable time (speaking of literal minutes that it takes to load and multiple seconds to perform a single map check, depending on how much entries the map types there have).

This ultimately lead me into bending the interpreter language to perform position checks in the time of 0.01 ms, but it came with the cost of alot of memory usage and that my tool is now leaking to memory.

This bothers me alot and im trying to see if Rust's datatypes, in this case the hashmap, can perform these actions better.

So i created a new rust project that is compiled into a .dll. I found by searching through this forum that i can create a hashmap and cross its pointer over the ffi border like this

#[no_mangle]
pub extern fn create_hashmap() -> *mut HashMap<String, String> {
	let mut hashmap: HashMap<String, String> = HashMap::new();
	Box::into_raw(Box::new(hashmap))
}

I am not sure if this is the only way of doing it, or even a good way. I am to new to low level programming to tell.

Now my problem is that i cant seem to find a way to convert this pointer back to a hasmap when i pass it back to the rust dll

#[no_mangle]
pub extern fn hashmap_add(hashmap: *const HashMap<String, String>) {
	let mut hashmap = Box::from_raw(hashmap as *mut HashMap<String, String>);
	
	hashmap.insert("Hello".to_string(), "World".to_string());
	
	for (pos, postype) in &hashmap {
		println!("pos: {} - type: {}", pos, postype);
	}
}

This throws &Box<HashMap<std::string::String, std::string::String>> is not an iterator`
I am dont know how to proceed.

I am looking for some Help (:

Have a nice one o/

You probably want hashmap.iter().

By the way, don't use Box::from_raw() in this function. That takes ownership of the raw pointer, and the box (along with the contained hash map) will be deallocated at the end of the function. That's not what you want in a function called hashmap_add() with overwhelming probability.

1 Like

Thats good to know, what do i use instead of Box::from_raw() to turn this ptr back to a hashmap that is not deallocated and that rust can work with. Because hashmap.insert("Hello".to_string(), "World".to_string()); does not work on hashmap: *const HashMap<String, String>

You dereference the pointer and take a (mutable) reference immediately.

2 Likes

Do you mean like this? (had to google what you where saying)

#[no_mangle]
pub extern fn hashmap_add(ptr: *mut HashMap<String, String>) {
	let hashmap = unsafe {
		&mut *ptr
	};
	
	hashmap.insert("Hello".to_string(), "World".to_string());
	
	for (pos, postype) in hashmap {
		println!("pos: {} - type: {}", pos, postype);
	}
}

Yes.

1 Like

Thanks alot! Played around with this since yesterday.

Checked that it works. Created the map, added something and then looked if its in there with another call.

#[no_mangle]
pub extern fn create_hashmap() -> *mut HashMap<String, String> {
	let mut hashmap: HashMap<String, String> = HashMap::new();
	Box::into_raw(Box::new(hashmap))
}

#[no_mangle]
pub extern fn hashmap_add(ptr: *mut HashMap<String, String>) {
	let hashmap = unsafe {
		&mut *ptr
	};
	
	hashmap.insert("Hello".to_string(), "World".to_string());
}

#[no_mangle]
pub extern fn hashmap_show(ptr: *mut HashMap<String, String>) {
	let hashmap = unsafe {
		&mut *ptr
	};
	
	for (pos, postype) in hashmap {
		println!("pos: {} - type: {}", pos, postype);
	}
}

#[no_mangle]
pub extern fn hashmap_free(ptr: *mut HashMap<String, String>) {
	unsafe {
		Box::from_raw(ptr);
	}
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.