I'm currently working on a VM inspired by interaction nets (a graph-based model of computation), and I need to use a lot of cyclic data structures with manual memory management, i.e. a lot of unsafe and raw pointers. And I'm finding that Rust is extremely painful for this use case. I think a lot of the pain would be alleviated by providing an ergonomic pointer-offset mechanism, which could be as simple as a field access. For example:
use std::ptr;
#[derive(Debug, Clone, Copy)]
struct Node(*mut Node, *mut Node);
fn main() {
let mut node = Node(ptr::null_mut(), ptr::null_mut());
let node_ptr = &mut node as *mut Node;
// let node_0_ptr = node_ptr.0; // Why not let this be pointer offset?
// Instead, I have to do this:
let node_0_ptr = unsafe { &mut (*node_ptr).0 as *mut _ };
}
When I want to get an interior pointer, I would like to be able to just do node_ptr.0
. Is there a reason this can't be supported?
It would also be nice if you could directly take a pointer using *mut node
rather than needing to do &mut node as *mut Node
, but I'm guessing supporting *mut node
would considerably complicate parsing (if not make it ambiguous). Luckily, that pain is at least alleviated by automatic coercion from &mut _
to *mut _
, and can be further alleviated by a user-defined macro.
In most instances I would use Vec and indexes rather than raw pointers, but this is a case where that would make the code even more opaque and less type safe (and less performant for large graphs, due to reallocation and memcopy). I need graphs of nodes with non-uniform size, with pointers to the interiors of other nodes.
I'm writing a low level VM with strict performance considerations. I currently use inlined functions to abstract away the pointer offset boilerplate, but I end up needing a separate function for each field of each node.
Also, it's perhaps worth noting that the current situation requires sprinkling unsafe everywhere, even though the operation, i.e. pointer offset, is not actually unsafe. This makes it more difficult to minimize the use of the unsafe
keyword, which will make future auditing of the unsafe code more difficult.
Note: I had originally posted this on the users forum, but 2e71828 helpfully pointed out that this would be a better location.