Impl Match for my struct? or if let?

I would appreciate some assistance rustifactoring this solution. I have InvocableCategoryList that has a Vec of InvocableCategory, where each InvocableCategory has a Vec of Invocable, where each Invocable has a String field named command_code. I need to match a value against this command_code string.

This is my current ridiculousness:

    for category in category_list.categories.iter() {
        for invocable in category.invocables.iter() {
            if invocable.command_code == config.command_code {
                Invoker{}.invoke(invocable, config.dry_run, config.verbose, config.cmd_args);
                std::process::exit(0); // TODO: return result from invoking command
            }
        }
    }

The compare of the value config.command_code against those deeply nested values seems like a possible use of the Match trait, but I would like to confirm that this is the right direction, and I can't even predict the syntax for how I would use the result as shown with the Invoker? Is there another/better solution than basically moving the for loops into the Match trait and returning an Invoker in the case of a match? It would not make sense to me logically, but would altering the data structures in some way help, for example storing command_code in InvocableCategoryList rather than Invocable?

The closest thing I have found is this, but it seems to be specific to wiremock, which I don't want and may be irrelevant anyway.

impl Match for OddHeaderMatcher {
    fn matches(&self, request: &Request) -> bool {
        match request.headers.get(&self.0) {
            // We are ignoring multi-valued headers for simplicity
            Some(values) => values[0].as_str().len() % 2 == 1,
            None => false
        }
    }
}

Whether by implementing Match or otherwise, maybe I am looking for something that uses if let to get the Invoker that matches command_code, where no match is an error case for which I show the user help after some additional logic between those for loops and exiting the program.

Or maybe TryFrom, converting command_code to an Invoker?

TryFrom in std::convert - Rust (rust-lang.org)

Your goals are unclear to me. Are you just trying to simplify the code? If so, you could do something like this:

/// Finds and returns the first matching `Invocable`, or `None`
impl InvocableCategoryList {
    pub fn find_command_code(&self, command_code: &str) -> Option<&Invocable> {
        self.categories
            .iter()
            .flat_map(|c| c.invocables.iter())
            .find(|i| i.command_code == command_code)
    }
}

And then elsewhere

if let Some(invocable) = category_list.find_command_code(&config.command_code) {
    // Use the invocable
} else {
    // Handle the "missing command code" error case
}
1 Like

Thanks! I do not have a specific goal. I am just learning rust and wondering how others would approach this problem. If what you showed looks typical, then that is enough for me.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.