I’m currently implementing a toy language and library in Rust, dealing with data flows of lists and matrices. Still figuring out what the best way to implement this, but I’m currently thinking of generating all relevant functions up front and then picking the right one at runtime.
Say I have some data types: {f32, Vec2, Vec3 etc.}
(where the Vec2/Vec3 are just [f32; n], like those in Glam). I’m actually using Glam, so I have the correct implementations of Add/Mult etc. at my disposal. I can do f32 + Vec3 -> Vec3
, Vec3 + Vec3 -> Vec3
etc.
Now I'm making a generic function that will accept slices of them, so that if I can do A+B=C
I can do Multi<A> + Multi<B> = Multi<C>
by doing c[i] = a[i] + b[i]
(and later on combinations of this, such as Multi<A> + B = Multi<C>
):
pub fn add_inplace<A, B>(a: &[A], b: &[B], c: &mut [<A as Add<B>>::Output])
where
A: Copy,
B: Copy,
A: Add<B>,
{
assert_eq!(a.len(), b.len());
for i in 0..a.len() {
c[i] = a[i] + b[i];
}
}
But this function is generic, meaning that it doesn't actually exist yet, although rustc knows how to generate the code for it. Rust generates the concrete implementation whenever I call the function in my code somewhere (the so-called monomorphization).
Now my use-case is a bit special. At runtime, I want to lookup the actual function that I want to call and call it using some unsafe trickery (comparable to a dylib). This means that I need Rust to somehow generate concrete versions of all possible implementations of this function:
// Obviously pseudo-code
let mut functions_library = HashMap::new();
for Type1 in <f32, Vec2, Vec3> { // Iterate over all types
for Type2 in <f32, Vec2, Vec3> {
let key = ("+", Type1, Type2); // Lookup consists of the function name and the input types
// let return_type = add_inplace<Type1, Type2>::ReturnType // question 2: does something like this exist??
let func_ptr = add_inplace<Type1, Type2>; // The function ptr, e.g. add_inplace<Vec3, f32>
functions_library.insert(key, func_ptr as *const c_void);
}
}
The goal being a function pointer to the monomorphized function stored in a hashmap. Are there ways to use Rust (or perhaps rustc directly) as a code generator in this fashion, so that all possible instantiations end up compiled and retrievable in some way? Do you know of any blog posts or crates that do something like this?
Second question, is there a way to get the return type of an generic function, so something like add_inplace<Type1, Type2>::ReturnType
?