0

I have an implementation for a struct that needs to be implemented on multiple structs with an argument for every struct.

My impl statement is as follows:

#[rocket::async_trait]
impl<'r> FromRequest<'r> for ReadMe {
    type Error = AuthErrors;

    async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
        let db = request
            .guard::<&State<mongodb::Database>>()
            .await
            .expect("No database state!");
        let token = request.headers().get_one("Authorization");

        match token {
            Some(token) => {
                // check validity
                let user = get_user_by_token(token.to_string(), db.inner().to_owned()).await;

                match user {
                    Some(user) => {
                        if user.tokenData.scopes.split(" ").any(|x| x == "ReadMe") {
                            Outcome::Success(ReadMe(Some(BasicScope {
                                user: user.user,
                                value: true,
                            })))
                        } else {
                            Outcome::Failure((Status::Forbidden, AuthErrors::ScopeMissing))
                        }
                    }
                    None => Outcome::Failure((Status::Unauthorized, AuthErrors::Invalid)), // TODO?: Should this return something else?
                }
            }
            None => Outcome::Failure((Status::Unauthorized, AuthErrors::Missing)),
        }
    }
}

The reason this would benefit from being a macro is that I will have a lot of structs that need a slightly modified version of that implementation ("ReadMe" has to be different for every struct). Instead of copy and pasting this implementation, each one being slightly modified it would be cleaner to do #[derive(Scope("ReadMe"))].

How could this be transformed in to a macro I can reuse?

piano1029
  • 21
  • 4
  • 3
    You should elaborate on your requirements here, as is I'm not seeing what part of this would benefit from translation to a macro. Maybe include a second example to indicate what code would be duplicated and what would differ? (Try to simplify it if you can, minimal reproducible example and all.) – Edward Peters Nov 21 '22 at 13:56
  • 1
    @EdwardPeters Thanks! Ive updated my question to include the differences and explain why it would benefit from being a macro. – piano1029 Nov 21 '22 at 13:59
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Community Nov 21 '22 at 16:58
  • If the only difference between implementations is a `&str` then you could just write a function `from_request_and_str(request: &'r Request<'_>, readme_name: &str))` and delegate to that. If the following code should be different too, you could add another argument of type `impl Fn() -> ReadMe` or whatever you need. Generally speaking, you should consider a non-macro solution before going down that rabbit-hole. – rodrigo Nov 21 '22 at 17:14
  • @rodrigo The implementation is used by a framework (Rocket) which is out of my control and because of that that won’t work sadly – piano1029 Nov 21 '22 at 17:29
  • Maybe you could add two different implementations of your would-be generated code, so that we can see what code is duplicated and what code is different? – rodrigo Nov 21 '22 at 17:58

0 Answers0