ibraheemdev / matchit

A high performance, zero-copy URL router.
https://docs.rs/matchit
MIT License
366 stars 37 forks source link

Build router as a compile time constant #26

Closed infogulch closed 1 year ago

infogulch commented 2 years ago

Hi! I'd like to use matchit in a webassembly module that is recycled after every request completes, and I'd prefer not to pay the cost to build the whole router on every request. Ideally I'd like to create a router at compile time and save it as a non-mut static variable, then use it by calling .at on it directly. (As a bonus this may allow LTO to eliminate everything but the .at method, trimming out all of the radix tree building code.)

I'm currently doing this:

static ROUTER: Lazy<Router<fn(&Request) -> String>> = Lazy::new(|| {
    let mut router: Router<fn(&Request) -> String> = Router::new();
    router.insert("/", index).unwrap();
    router.insert("/some/page", some_page).unwrap();
    router
});

I asked about this in #rust:matrix.org and presumably it's possible in theory if Vecs were switched out for slices internally (as a start, who knows what else). I think it would be a neat feature, but whether it's worth inflicting this scale of change on the library is an entirely different question. For now I will not worry about this minor 'inefficiency', but I thought I'd bring it up here to get your opinion.

What do you think? Useful? Feasible?

ibraheemdev commented 2 years ago

Constructing the radix tree is pretty complex and with all of the current const limitations I don't think it would work. A proc-macro might, but if all your routes are known at compile-time there are probably more efficient ways to perform the lookup than using a static radix tree, so I'm not sure it's worth the trouble.

(Also the Vecs would have to be switched out for arrays not slices, and they are potentially different lengths for each node so you would have to do something hacky like choose a global maximum length for all arrays).

infogulch commented 1 year ago

there are probably more efficient ways to perform the lookup than using a static radix tree

I guess you could use some kind of PHF but I'd need something to parse out path variables, which seems too specialized.

Constructing the router in a proc macro seems like a reasonable strategy.

ibraheemdev commented 1 year ago

This isn't something that I think matchit will support, feel free to reopen this issue if you have further thoughts.