Simple command line parser/dispatcher in Rust
Prefer where clauses when your bounds get the tiniest bit complicated
An if let with an else is often better as a match.
If you match on an Option and return an Option, just use Option::map.
This allows you to remove the temporary variable and just chain functions
The tests module should have #[cfg(test)] to prevent it from even being compiled when not testing.
It's typical to use super::* in a test module.
It's better to let the compiler infer types instead of being explicit. This shows as an error because the compiler can't infer the error type. You could say cmdr: Cmdr&lt;_, &amp;str&gt;, but it's better to actually exercise the error case.
Instead of unwrapping your success / failure, assert against them.
Use assert_eq instead of assert when comapring equality.
Use assert! and is_none instead of pattern matching


lib.rs

pub mod cmd;
use cmd::Cmd;

pub struct Cmdr&lt;T, E&gt; {
    cmds: Vec&lt;Cmd&lt;T, E&gt;&gt;,
}

impl&lt;T, E&gt; Cmdr&lt;T, E&gt; {
    pub fn new() -&gt; Cmdr&lt;T, E&gt; {
        Cmdr { cmds: Vec::new() }
    }

    pub fn add&lt;F&gt;(&amp;mut self, name: &amp;str, cmd: F)
    where
        F: FnMut() -&gt; Result&lt;T, E&gt; + 'static,
    {
        self.cmds.push(Cmd::new(name, cmd));
    }

    pub fn invoke(&amp;mut self, cmd_name: &amp;str) -&gt; Option&lt;Result&lt;T, E&gt;&gt; {
        self.cmds.iter_mut()
            .find(|cmd| cmd.name == cmd_name)
            .map(|cmd| cmd.invoke())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn cmdr() {
        let mut cmdr = Cmdr::new();
        cmdr.add("test1", || Ok("test1 executed."));
        cmdr.add("test2", || Err(42));

        // Good commands.
        let test1_msg = cmdr.invoke("test1");
        assert_eq!(test1_msg, Some(Ok("test1 executed.")), "Incorrect test1 message.");

        let test2_msg = cmdr.invoke("test2");
        assert_eq!(test2_msg, Some(Err(42)));

        // Bad command.
        assert!(cmdr.invoke("ghost").is_none(), "Non-existent command somehow returned Some().");
    }
}


cmd.rs

pub struct Cmd&lt;T, E&gt; {
    pub name: String,
    pub invocation: Box&lt;FnMut() -&gt; Result&lt;T, E&gt;&gt;,
}

impl&lt;T, E&gt; Cmd&lt;T, E&gt; {
    pub fn new&lt;F&gt;(invoke_str: &amp;str, invocation: F) -&gt; Cmd&lt;T, E&gt;
    where
        F: FnMut() -&gt; Result&lt;T, E&gt; + 'static,
    {
        Cmd {
            name: String::from(invoke_str),
            invocation: Box::new(invocation),
        }
    }

    pub fn invoke(&amp;mut self) -&gt; Result&lt;T, E&gt; {
        (self.invocation)()
    }
}





  I'm not sure that Cmdr should be living in the root lib.rs file. 


In fact, I'd say the opposite is true: I'm not sure that Cmd belongs in it's own file. Unlike many languages, most Rust projects I've read have no hesitation in placing more than one type in a single file. I wouldn't think that Cmd carries enough weight to be separated.

There is some work underway to adjust Rust's module system, so the organization you've shown might return to vogue at some point.


  my namespace would be something stupid like cmdr::cmdr::Cmdr, as my root directory is also named cmdr


You can use the façade pattern to re-export nested types at a higher module:

// lib.rs
pub use cmdr::Cmdr;



  Option&lt;Result&lt;T, E&gt;&gt;


I'd encourage you to try this out a bit; my gut tells me that it won't be the most ergonomic to use.


  Document the code in a Rusty style


Remember that the static type system provides a baseline of documentation and that function and argument names provide a bit more. Don't document the things that are obvious from the name or type of something. Consider making more types to improve the documentation and user experience.


  Eventually, this will be a front end for a DHCP client/server package I'd like to implement in Rust. I may also release it on crates.io, if it matures into something worthwhile.


Please strongly consider not using your own hand-rolled library for such a project. Having a great DHCP server sounds wonderful, but one where the author's time has to be spent maintaining a command-line parsing library or  one that has a substandard command line interface would detract from it.

Of course, that shouldn't stop you from using it to experiment with Rust!