I'm writing a little library for parsing OVPN config files. OVPN config files have this format
command arg1 arg2
othercommand arg1 arg2
There's a fixed set of commands, some of them have optional arguments. I want to represent the parsed commands as an enum. So the above might end up being represented like this:
enum ConfigDirective{
Command{arg1: String},
OtherCommand{arg1: String, optinal_arg1: Option<String>},
}
fn parse_line(command: String, args: Vec<String>) -> ConfigDirective {
match command {
"command" => ConfigDirective::Command{arg1: args[0]},
"other_command" => ConfigDirective:OtherCommand{arg1: args[0], optional_arg1: args.get(1),
}
}
I like this structure but there are a lot of possible commands (somewhere in the region of 280). So I want to write a macro to generate most of the boilerplate. Ideally I would write something like the following:
define_config_directive!{
{command => "command1", rust_name => CommandOne, args => [arg1], optional_args => []},
{command => "other_command", rust_name => OtherCommand, args => [arg1], optional_args => [optional_arg1]},
}
The closest I've been able to get so far is this:
macro_rules! define_config_directives {
($({
rust_name => $rust_name:ident,
required => [$($required:ident),*],
optional => [$($optional:ident),*]
}),*) => {
#[derive(PartialEq, Eq, Debug)]
pub enum ConfigDirective {
$($rust_name{
$($required: String),*,
$($optional: Option<String>),*,
}),*
}
};
}
So I have a few problems:
- I don't know how to implement the
parse_linefunction in this macro, I need to iterate over each required argument in order writing some code to pull the corresponding argument out of the line and the same for optional arguments - I don't know how to handle situations where there are no arguments at all, ideally that would be a simple enum variant without fields.
Does anyone know if there's a way to solve this on stable rust? Or should I just generate the code using a python script?
build.rsfile. When usingcargo build, cargo will first compile and executebuild.rs(if present) before compiling the rest of your crate, so you can easily usebuild.rsto generate Rust code without involving any 3rd party tooling/makefile. - Matthieu M.