Genrate function from code spread over multiple blocks/files

for my current needs, when I create a function I need to add it to a map(match function) and create a entry in dict.rs for that function.

file1.rs:-

fn login(data: Data) {} //a special function somewhere in middle of this file

file2.rs:-

fn register(data: Data) {} //another special function

dict.rs :-

//need to add entry for each special function with unique numbers
pub const LOGIN : u16 = 1 
pub const REGISTER : u16 = 2

route.rs :-

use crate::dict;
// and then add it to the map
fn route_map(function){
    match function {
        dict::LOGIN => auth::login(route_data),
        dict::REGISTER => auth::register(route_data),
        _unknown => {}
    }
}

I have to repeat this for all special functions and I believe this will soon get messy. is there any way I by pass all the code in route.rs and dict.rs and genrate at compile time by some macros ? something like Qt's moc compiler ?

something like this:-

#[CoolFn]
fn login() {}

and then other code is generated at compile time.

How can I achieve this ? if not I'm open to other possible solution to reduce the code

It might be possible to do what you want with a custom build.rs, but it would be quite a bit of ugly code.

On the other hand, if you could fold all of your routes into a single file, and your names into a single enum:

#[derive(RouteMap)]
enum Routes {
    Login,
    Register,
    // ...
}

fn login(data: Data) { /* ... */ }
fn register(data: Data) { /* ... * }

Then it would be possible to write a RouteMap derive procedural macro generate a Routes::route_map function for you, matching Login to login(...), etc.

For that approach, I recommend the derive(Builder) procedural macro exercise on GitHub as a starting point.


On a separate note, if your goal is to run a Rust webserver, rather than writing one yourself, I would recommend Rocket. It works similarly to how you describe, but does require one "complete route table" in one spot.

Also, if it's multiple files that you specifically require, it is possible to have the procedural macro parse that from the enum -- invalid Rust syntax, but the macro can still read it:

#[route_map]
enum Routes {
    Login => crate::file1::login,
    Register => crate::file2:register,
    // ...
}

In that case, your macro would completely re-write the enum afterwards.

Still, no matter how you slice it, you do need to group all the routes you write together at some point.

1 Like