#[macro_export]
macro_rules! helper {
(exists_or_zero;) => {
1
};
(exists_or_zero;$t:tt) => {
$t
};
(exists;,$then:ty) => {
$then
};
(exists;$t:tt, $then:ty) => {
Vec<$then>
};
(exists_flag;,$then:ty) => {
Option<$then>
};
(exists_flag;$t:tt, $then:ty) => {
Vec<$then>
};
(exists_add;,$var:ident, $type:ty, $d:ident, $db:ident) => {
$var = <$type>::from($d.get($db).expect("this is an error on line 22, please report this bug").clone());
$d.remove($db);
};
(exists_add;$t:tt,$var:ident, $type:ty, $d:ident, $db:ident) => {
for _ in 0..$t {
$var.push(<$type>::from($d.get($db).expect("this is an error on line 27, please report this bug").clone()));
$d.remove($db);
}
};
(exists_add_flag;,$var:ident, $type:ty, $d:ident, $db:expr) => {
$var = Some(<$type>::from($d.get($db).expect("this is an error on line 32, please report this bug").clone()));
$d.remove($db);
};
(exists_add_flag;$t:tt,$var:ident, $type:ty, $d:ident, $db:expr) => {
for _ in 0..$t {
$var.push(<$type>::from($d.get($db).expect("this is an error on line 37, please report this bug").clone()));
$d.remove($db);
}
};
(exists_declare;,$var:ident, $type:ty) => {
let $var: $type;
};
(exists_declare;$t:tt,$var:ident, $type:ty) => {
let mut $var: Vec<$type> = Vec::new();
};
(exists_declare_flag;,$var:ident, $type:ty) => {
let mut $var: Option<$type> = None;
};
(exists_declare_flag;$t:tt,$var:ident, $type:ty) => {
let mut $var: Vec<$type> = Vec::new();
};
}
#[macro_export]
macro_rules! cmd {
($name:ident; help:$help:expr; default: $default:ident; $($fname:ident => $($str:literal)|*),*$(,)?) => {
struct $name;
impl $name {
pub fn run(v: Vec<String>) {
let cmd = v.get(0).expect(&format!("{}", $help)).clone();
if cmd == "help" {
println!("{}", $help);
std::process::exit(0);
} else
$(
if $(cmd == $str)||* {
$fname(v);
} else
)* {
$default(v);
}
}
}
};
($name:ident; help:$help:expr; $($fname:ident => $($str:literal)|*),*$(,)?) => {
pub fn _default(_: Vec<String>) {
eprintln!("{}", $help);
std::process::exit(101);
}
$crate::cmd!{
_Main;
help:$help;
default: _default;
$($fname => $($str)|*),*
}
};
(help:$help:expr; $(default: $default:ident;)? $($fname:ident => $($str:literal)|*),*$(,)?) => {
fn main() {
_Main::run(std::env::args().skip(1).collect());
}
$crate::cmd!{
_Main;
help:$help;
$(default:$default;)?
$($fname => $($str)|*),*
}
};
}
#[macro_export]
macro_rules! define {
($name:ident; help: $help:expr; flags {
$($fname:ident: $ftype:ty = $($flag:literal)|* $(=> [$fnum:literal])?),*$(,)?
}; args {
$($aname:ident: $atype:ty $(=> [$num:literal])?),*$(,)?
};
$(rest => $rname:ident: $rtype:ty;)?) => {
#[derive(Debug, Clone)]
struct $name {
$($fname: tt_call::tt_if!{
condition = [{tt_equal::tt_equal}]
input = [{ $ftype bool }]
true = [{
bool
}]
false = [{
$crate::helper!(exists_flag;$($fnum)?, $ftype)
}]
},)*
$(
$aname: $crate::helper!(exists;$($num)?, $atype),
)*
$(
$rname: Vec<$rtype>
)?
}
impl $name {
pub fn from(mut __args: Vec<String>) -> Self{
let mut __handle_flags = true;
$(
tt_call::tt_if!{
condition = [{tt_equal::tt_equal}]
input = [{ $ftype bool }]
true = [{
let mut $fname: bool = false;
}]
false = [{
$crate::helper!(exists_declare_flag;$($fnum)?, $fname, $ftype);
}]
}
)*
$(
$crate::helper!(exists_declare;$($num)?,$aname, $atype);
)*
$(
let mut $rname: Vec<$rtype> = Vec::new();
)?
if __args.contains(&"-help".to_string()) || __args.contains(&"--help".to_string()) {
eprintln!("{}", $help);
std::process::exit(0);
}
let mut __i = 0;
$(
if __args.len() == 0 {
eprintln!("missing argument: '{}'", stringify!($aname));
std::process::exit(101);
}
while __args.get(__i).expect("there is an error on line 146, please report this bug").starts_with("-") && __handle_flags {
let v = Self::has_args(__args.get(__i).expect("there is an error on line 147, please report this bug").clone());
__args.get_mut(__i).expect("there is an error on line 148, please report this bug").insert(0, '-');
if v.0 {
__i += v.1;
if __args.get(__i).expect("there is an error on line 151, please report this bug").starts_with("-") && __handle_flags {
eprintln!("the flag requires an argument");
std::process::exit(101);
}
}
__i += 1;
}
$crate::helper!(exists_add; $($num)?, $aname, $atype, __args, __i);
)*
$(
while __args.len() - __i > 0 {
if __args.get(__i).expect("there is an error on line 163, please report this bug").starts_with("-") && __handle_flags {
if $rname.len() > 0 {
break;
}
while __args.get(__i).unwrap_or(&String::new()).starts_with("-") && __handle_flags {
let v = Self::has_args(__args.get(__i).expect("there is an error on line 168, please report this bug").clone());
if __args[__i] == "--" {
__handle_flags = false;
__args.remove(__i);
break;
}
__args.get_mut(__i).expect("there is an error on line 169, please report this bug").insert(0, '-');
if v.0 {
__i += v.1;
if __args.get(__i).unwrap_or(&String::from("-")).starts_with("-") && __handle_flags {
eprintln!("the flag requires an argument");
std::process::exit(101);
}
}
__i += 1;
}
}
if let Some(s) = __args.get(__i) {
$rname.push(<$rtype>::from(s.clone()));
__args.remove(__i);
}
}
)?
while __args.len() > 0 {
let mut __ch = __args.get(0).expect("there is an error on line 186, please report this bug").clone();
if !(__ch.starts_with("-") && __handle_flags) {
eprintln!("too many arguments");
std::process::exit(101);
}
__ch.remove(0);
if __ch.starts_with("-") && __handle_flags {
__ch.remove(0);
}
$(
if $(__ch == $flag)||* {
tt_call::tt_if!{
condition = [{tt_equal::tt_equal}]
input = [{ $ftype bool }]
true = [{
$fname = true;
}]
false = [{
if __args[1].starts_with("-") && __handle_flags {
eprintln!("flags requires an argument");
std::process::exit(101);
}
$crate::helper!(exists_add_flag;$($fnum)?, $fname, $ftype, __args, 1);
}]
}
__args.remove(0);
continue;
} else
)*
if (__ch == "-") {
__handle_flags = false;
__args.remove(0);
break
}
eprintln!("invalid flag {}", __ch);
std::process::exit(101);
}
return Self {
$($fname,)*
$($aname,)*
$($rname)?
}
}
fn has_args(v: String) -> (bool, usize) {
$(
if $(v == concat!("-", $flag) || v == concat!("--", $flag))||* {
tt_call::tt_if!{
condition = [{tt_equal::tt_equal}]
input = [{ $ftype bool }]
true = [{
return (false, 0);
}]
false = [{
return (true, $crate::helper!(exists_or_zero;$($fnum)?));
}]
}
} else
)*
if(v == "--") {
return (false, 0);
}
eprintln!("invalid flag {}", v);
std::process::exit(101);
}
}
};
}