Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Router refactor #307

Merged
merged 4 commits into from
Nov 20, 2022
Merged

Router refactor #307

merged 4 commits into from
Nov 20, 2022

Conversation

AntoineRR
Copy link
Collaborator

Description

This PR refactors the routers module of the Rust part of Robyn.
I noticed some improvements could be made there so here is my take on it.

Noticeable changes:

  • Rename Router to DynRouter
  • Introduce a Router trait to unify the behavior of ConstRouter, DynRouter, and MiddlewareRouter
  • Get rid of the get_relevant_map methods (mapping is directly done at structure creation)
  • Some parts of the code were made less verbose

I tried to keep the same logic as before. I think this could pave the way for further performance improvements for the router 🙂

@netlify
Copy link

netlify bot commented Nov 11, 2022

Deploy Preview for robyn canceled.

Name Link
🔨 Latest commit c0850a7
🔍 Latest deploy log https://app.netlify.com/sites/robyn/deploys/636f952bb222ea0008cec5d1

@sansyrox
Copy link
Member

@AntoineRR , great work. I will try to review this PR by today evening 😄


/// Checks if the functions is an async function
/// Inserts them in the router according to their nature(CoRoutine/SyncFunction)
impl Router<String, Method> for ConstRouter {
Copy link
Member

@sansyrox sansyrox Nov 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @AntoineRR ,

I am a bit unfamiliar with traits in rust. Can you please explain this statement to me? And the benefits associated with it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure !

About traits

Traits are a way in Rust to share behavior between structs. There is no inheritance in Rust as in a truly object oriented language like C++, so traits are more similar to interfaces in Java for example.

Here, defining the Router trait allows to specify what methods should be in a router : add_route and get_route. For every router we want to define, we have to implement this trait using the line above. This will force us to provide a definition for the add_route and get_route method that is specific to our struct, which is ConstRouter here.

About the generics

I didn't want to change the code too much so I kept the same return types and parameter types in every router struct. The return type of the get_route method is different across the routers (DynRouter and MiddlewareRouter return an Option<((PyFunction, u8), HashMap<String, String>)> while ConstRouter return an Option<String>), so I used a generic type to unify their behavior in the trait. Similarly, the route_type parameter of the get_route method can either be a MiddlewareRoute or a Method. I needed two different generic types to handle those differences: this is T and U in the definition of the trait : pub trait Router<T, U>. For ConstRouter, T is String and U is Method.

Benefits of using traits

With this PR, DynRouter, ConstRouter and MiddlewareRouter all implement the Router trait (I wanted to include the WebSocketRouter too but it seems too different from the others). This means the compiler is aware those share some behavior. We could now do some cool things like:

  • Creating a Vec<dyn Router> containing the routers
  • Create generic methods that take a type implementing the Router trait as parameter -> fn method<T: Router>(router: T)
  • Eventually provide a default implementation for the add_route and get_route methods if we can make it the same for all structs (which I may try to do later)
  • If a new method needs to be added for every router, its implementation can be in the Router trait instead of in each struct
  • Maybe other things I forgot?

I hope this makes things clearer! In this PR I didn't take advantage of the trait for now, I wanted to do small iterations on the code instead of a really big one. I will try to improve things further if I have some time 😉

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @AntoineRR . This an excellent explanation 😄

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're welcome ! 😉

Copy link
Member

@sansyrox sansyrox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR @AntoineRR :D . I have a few inline comments.

Copy link
Member

@sansyrox sansyrox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! 🚀 Great work.

But I am holding this PR to allow (#297) to merge.

@AntoineRR
Copy link
Collaborator Author

Ok thanks! I'll solve the eventual merge conflicts once the other PR is merged

@sansyrox
Copy link
Member

Looks like the other PR is gonna take some time.

Great job on this one!

@sansyrox sansyrox merged commit 1bb9940 into sparckles:main Nov 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants