#[macro_export]
macro_rules! extract {
($result:expr, { $($body:tt)* }) => {{
let __res = &$result;
(|| {
#[allow(unused_mut, unused_variables)]
let mut __pos_idx: usize = 0;
#[allow(unused_variables)]
let __positionals = __res.get_positionals();
$crate::extract!(@normalize __res, __pos_idx, __positionals,
{ $($body)* }
)
})()
}};
(@normalize $res:expr, $pos_idx:ident, $positionals:ident,
{ $($body:tt)* }
) => {
$crate::extract!(@munch $res, $pos_idx, $positionals,
{ }
{ }
{ }
$($body)* ,
)
};
(@munch $res:expr, $pos_idx:ident, $positionals:ident,
{ $($bindings:tt)* }
{ $($struct_fields:tt)* }
{ $($names:ident)* }
$field_name:ident : bool , $($rest:tt)*
) => {
$crate::extract!(@munch $res, $pos_idx, $positionals,
{
$($bindings)*
let $field_name: bool = {
let __name = stringify!($field_name).replace('_', "-");
$res.get_flag(&__name)
};
}
{
$($struct_fields)*
pub $field_name : bool,
}
{ $($names)* $field_name }
$($rest)*
)
};
(@munch $res:expr, $pos_idx:ident, $positionals:ident,
{ $($bindings:tt)* }
{ $($struct_fields:tt)* }
{ $($names:ident)* }
$field_name:ident : Option < $inner:ty > as @ pos , $($rest:tt)*
) => {
$crate::extract!(@munch $res, $pos_idx, $positionals,
{
$($bindings)*
let $field_name: Option<$inner> = {
let __name = stringify!($field_name);
if $pos_idx < $positionals.len() {
let __val = $positionals[$pos_idx].parse::<$inner>().map_err(|e| $crate::OptionError::ParseFailed {
option: __name.to_string(),
message: e.to_string(),
})?;
$pos_idx += 1;
Some(__val)
} else {
None
}
};
}
{
$($struct_fields)*
pub $field_name : Option<$inner>,
}
{ $($names)* $field_name }
$($rest)*
)
};
(@munch $res:expr, $pos_idx:ident, $positionals:ident,
{ $($bindings:tt)* }
{ $($struct_fields:tt)* }
{ $($names:ident)* }
$field_name:ident : Option < $inner:ty > , $($rest:tt)*
) => {
$crate::extract!(@munch $res, $pos_idx, $positionals,
{
$($bindings)*
let $field_name: Option<$inner> = {
let __name = stringify!($field_name).replace('_', "-");
match $res.get_option(&__name) {
Some(v) => Some(v.parse::<$inner>().map_err(|e| $crate::OptionError::ParseFailed {
option: __name.clone(),
message: e.to_string(),
})?),
None => None,
}
};
}
{
$($struct_fields)*
pub $field_name : Option<$inner>,
}
{ $($names)* $field_name }
$($rest)*
)
};
(@munch $res:expr, $pos_idx:ident, $positionals:ident,
{ $($bindings:tt)* }
{ $($struct_fields:tt)* }
{ $($names:ident)* }
$field_name:ident : Vec < $inner:ty > as @ pos , $($rest:tt)*
) => {
$crate::extract!(@munch $res, $pos_idx, $positionals,
{
$($bindings)*
let $field_name: Vec<$inner> = {
let __name = stringify!($field_name);
let __slice = &$positionals[$pos_idx..];
let __parsed: Vec<$inner> = __slice.iter().map(|v| v.parse::<$inner>()).collect::<Result<Vec<$inner>, _>>().map_err(|e| $crate::OptionError::ParseFailed {
option: __name.to_string(),
message: e.to_string(),
})?;
$pos_idx = $positionals.len();
__parsed
};
}
{
$($struct_fields)*
pub $field_name : Vec<$inner>,
}
{ $($names)* $field_name }
$($rest)*
)
};
(@munch $res:expr, $pos_idx:ident, $positionals:ident,
{ $($bindings:tt)* }
{ $($struct_fields:tt)* }
{ $($names:ident)* }
$field_name:ident : Vec < $inner:ty > , $($rest:tt)*
) => {
$crate::extract!(@munch $res, $pos_idx, $positionals,
{
$($bindings)*
let $field_name: Vec<$inner> = {
let __name = stringify!($field_name).replace('_', "-");
let __raw = $res.get_option_values(&__name);
__raw.iter().map(|v| v.parse::<$inner>()).collect::<Result<Vec<$inner>, _>>().map_err(|e| $crate::OptionError::ParseFailed {
option: __name.clone(),
message: e.to_string(),
})?
};
}
{
$($struct_fields)*
pub $field_name : Vec<$inner>,
}
{ $($names)* $field_name }
$($rest)*
)
};
(@munch $res:expr, $pos_idx:ident, $positionals:ident,
{ $($bindings:tt)* }
{ $($struct_fields:tt)* }
{ $($names:ident)* }
$field_name:ident : $ty:ty as @ pos = $default:expr , $($rest:tt)*
) => {
$crate::extract!(@munch $res, $pos_idx, $positionals,
{
$($bindings)*
let $field_name: $ty = {
let __name = stringify!($field_name);
if $pos_idx < $positionals.len() {
let __val = $positionals[$pos_idx].parse::<$ty>().map_err(|e| $crate::OptionError::ParseFailed {
option: __name.to_string(),
message: e.to_string(),
})?;
$pos_idx += 1;
__val
} else {
$default
}
};
}
{
$($struct_fields)*
pub $field_name : $ty,
}
{ $($names)* $field_name }
$($rest)*
)
};
(@munch $res:expr, $pos_idx:ident, $positionals:ident,
{ $($bindings:tt)* }
{ $($struct_fields:tt)* }
{ $($names:ident)* }
$field_name:ident : $ty:ty as @ pos , $($rest:tt)*
) => {
$crate::extract!(@munch $res, $pos_idx, $positionals,
{
$($bindings)*
let $field_name: $ty = {
let __name = stringify!($field_name);
if $pos_idx < $positionals.len() {
let __val = $positionals[$pos_idx].parse::<$ty>().map_err(|e| $crate::OptionError::ParseFailed {
option: __name.to_string(),
message: e.to_string(),
})?;
$pos_idx += 1;
__val
} else {
return Err($crate::OptionError::Missing { option: __name.to_string() });
}
};
}
{
$($struct_fields)*
pub $field_name : $ty,
}
{ $($names)* $field_name }
$($rest)*
)
};
(@munch $res:expr, $pos_idx:ident, $positionals:ident,
{ $($bindings:tt)* }
{ $($struct_fields:tt)* }
{ $($names:ident)* }
$field_name:ident : $ty:ty as $custom_name:literal = $default:expr , $($rest:tt)*
) => {
$crate::extract!(@munch $res, $pos_idx, $positionals,
{
$($bindings)*
let $field_name: $ty = {
let __name: &str = $custom_name;
$res.get_option_or_default::<$ty>(__name, $default)?
};
}
{
$($struct_fields)*
pub $field_name : $ty,
}
{ $($names)* $field_name }
$($rest)*
)
};
(@munch $res:expr, $pos_idx:ident, $positionals:ident,
{ $($bindings:tt)* }
{ $($struct_fields:tt)* }
{ $($names:ident)* }
$field_name:ident : $ty:ty as $custom_name:literal , $($rest:tt)*
) => {
$crate::extract!(@munch $res, $pos_idx, $positionals,
{
$($bindings)*
let $field_name: $ty = {
let __name: &str = $custom_name;
$res.get_option_required::<$ty>(__name)?
};
}
{
$($struct_fields)*
pub $field_name : $ty,
}
{ $($names)* $field_name }
$($rest)*
)
};
(@munch $res:expr, $pos_idx:ident, $positionals:ident,
{ $($bindings:tt)* }
{ $($struct_fields:tt)* }
{ $($names:ident)* }
$field_name:ident : $ty:ty = $default:expr , $($rest:tt)*
) => {
$crate::extract!(@munch $res, $pos_idx, $positionals,
{
$($bindings)*
let $field_name: $ty = {
let __name = stringify!($field_name).replace('_', "-");
$res.get_option_or_default::<$ty>(&__name, $default)?
};
}
{
$($struct_fields)*
pub $field_name : $ty,
}
{ $($names)* $field_name }
$($rest)*
)
};
(@munch $res:expr, $pos_idx:ident, $positionals:ident,
{ $($bindings:tt)* }
{ $($struct_fields:tt)* }
{ $($names:ident)* }
$field_name:ident : $ty:ty , $($rest:tt)*
) => {
$crate::extract!(@munch $res, $pos_idx, $positionals,
{
$($bindings)*
let $field_name: $ty = {
let __name = stringify!($field_name).replace('_', "-");
$res.get_option_required::<$ty>(&__name)?
};
}
{
$($struct_fields)*
pub $field_name : $ty,
}
{ $($names)* $field_name }
$($rest)*
)
};
(@munch $res:expr, $pos_idx:ident, $positionals:ident,
{ $($bindings:tt)* }
{ $($struct_fields:tt)* }
{ $($names:ident)* }
) => {{
$($bindings)*
#[derive(Debug)]
struct __ExtractedFields {
$($struct_fields)*
}
Ok::<__ExtractedFields, $crate::OptionError>(__ExtractedFields {
$($names,)*
})
}};
(@munch $res:expr, $pos_idx:ident, $positionals:ident,
{ $($bindings:tt)* }
{ $($struct_fields:tt)* }
{ $($names:ident)* }
,
) => {{
$($bindings)*
#[derive(Debug)]
struct __ExtractedFields {
$($struct_fields)*
}
Ok::<__ExtractedFields, $crate::OptionError>(__ExtractedFields {
$($names,)*
})
}};
(@munch $res:expr, $pos_idx:ident, $positionals:ident,
{ $($bindings:tt)* }
{ $($struct_fields:tt)* }
{ $($names:ident)* }
$($rest:tt)*
) => {
compile_error!(concat!(
"extract!: unsupported field syntax. Check the field starting near: ",
stringify!($($rest)*)
))
};
}