I’m having trouble locating documentation relevant to your use case - I’ve found several lateral bugs that have been fixed. The documents are rather thin regarding this issue you’re facing and I’ve spent a good chunk of time looking at this point.
I’m going out on a limb and saying that the actual pointer casts are not UB - you’re covering the most common pain point already by using a usize (much of “implementation defined” stuff is in regards to the actual integer size itself).
Calling the function pointer itself may actually be UB though - again, I can find direct C documentation that basically tries to prohibit what you’re doing but there’s not a lot of obvious Zig documentation on it that I can find.
In general, I would avoid doing this. First like @kristoff mentioned, you could lose out on some optimizations (however, you’re in type-erasure territory so performance is already taking a big hit). I’m going to take this ever further though and say that you’ll almost always get better language support (including bug fixes) if you do things in a more recognizable way.