I'm learning rust, and a project idea I had was to write a command line parsing framework, that enables the use of commands and options. I have previously done this same project in other languages.
I have defined my option struct as such:
pub struct Arg<T: FromStr> {
// fields
}
In a command, I wish to store multiple Arg instances, that may have different generic types. To do this, I resorted to creating a non-generic trait for Arg<T>, to then store them as dyn Arguments.
pub trait Argument {
type Target: FromStr;
type ParseError;
// other trait members ...
}
This trait is implemented for Arg<T> as such:
impl<T: FromStr> Argument for Arg<T> {
type Target = T;
type ParseError = T::Err;
// other members ...
}
And inside my Command struct, I wished to store Argument instances like this:
pub struct Command {
args: Vec<Box<dyn Argument<Target = dyn Any, ParseError = dyn Any>>>
}
This compiles so far. However, when I have an actual Arg<T> instance, I can't seem to cast them to dyn Argument<Target = dyn Any, ParseError = dyn Any>. I realize this approach is flawed for multiple reasons, but I can't find a working solution that would enable the behaviour I'm looking for.
Is there a way to implement this behaviour?
I guess what you want to do is be able to create a template for how to parse one argument and put several in a vector. To do this, the template should not be something like
Box<dyn Argument>, it should be something likeBox<dyn ArgumentBuilder>.Furthermore, the error should probably not be
Box<dyn Any>, it should beBox<dyn ErrorTrait>whereErrorTraitdefines what you should be able to do with an error. For example, an error should probably implementstd::error::Error.Here is a proof of concept (playground):