Let’s say I have an std.mem.Allocator, which might or might not be a concrete MyAllocator. Is there some way I can “downcast” to MyAllocator (with appropriate runtime checks), so that I can take advantage of extra APIs provided by MyAllocator without necessary making the type of the allocator concrete throughout the stack?
I think I can do that by comparing whether vtable is the same as the one I have, using the code roughly like this:
But is this pattern sound? I know that comparing function pointers for equality is fraught with peril, at lest in Rust. What about Zig? Would the code above do what I want it to do, or are there any sleeping dragons?
What are you going to do if the allocator isn’t what you’re expecting? Presumably, just crash, at runtime, for something that should have been caught at compile time. I recomend creating your own interface, with the methods that you need. Make it so this interface can create a std’s Allocator. When you need to interface with code that expects the regular std’s Allocator, you just create one and pass it.
I think you would still want your own interface. Make the function pointers that you don’t require as optional. Make a convenience function that simply takes a normal allocator and creates your custom allocator, with the optional fields set to null.
Another possibility is to receive your allocator as anytype and check at compile time if it is your custom allocator or the std Allocator.
vtable is a field and its address is different in each Allocatorinstance. But you need a pointer that is different for each allocator concrete type but is the same for different instances of that same type. This is why @matklad is comparing all function pointers assigned in the vtable.
Is it truly global or static per CU? In general it is safer to compare values than addresses. Values here are addresses of alloc, resize and free and if all of them match hopefully it is not a false positive.