181 lines
5.3 KiB
Rust
181 lines
5.3 KiB
Rust
/*
|
|
* meli
|
|
*
|
|
* Copyright 2017 Manos Pitsidianakis
|
|
*
|
|
* This file is part of meli.
|
|
*
|
|
* meli is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* meli is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
//! Helper type for showing the exact reason why a command was invalid.
|
|
|
|
use super::*;
|
|
|
|
pub enum ArgCheck<const MIN: u8, const MAX: u8> {
|
|
Start { __func__: &'static str },
|
|
BeforeArgument { so_far: u8, __func__: &'static str },
|
|
Eof { so_far: u8, __func__: &'static str },
|
|
}
|
|
|
|
impl<const MIN: u8, const MAX: u8> ArgCheck<MIN, MAX> {
|
|
#[inline]
|
|
pub fn new(__func__: &'static str) -> Self {
|
|
Self::Start { __func__ }
|
|
}
|
|
|
|
#[inline]
|
|
pub fn start(&mut self, input: &[u8]) -> Result<(), CommandError> {
|
|
let Self::Start { __func__ } = *self else {
|
|
unreachable!(
|
|
"ArgCheck::start called with invalid variant: {}",
|
|
if matches!(self, Self::BeforeArgument { .. }) {
|
|
"BeforeArgument"
|
|
} else {
|
|
"Eof"
|
|
}
|
|
);
|
|
};
|
|
let is_empty = input.trim().is_empty();
|
|
if is_empty && MIN > 0 {
|
|
return Err(CommandError::WrongNumberOfArguments {
|
|
too_many: false,
|
|
takes: (MIN, MAX.into()),
|
|
given: 0,
|
|
__func__,
|
|
inner: format!(
|
|
"needs {}{} arguments.",
|
|
if MIN == MAX { "at least " } else { "" },
|
|
MIN
|
|
)
|
|
.into(),
|
|
});
|
|
}
|
|
*self = Self::BeforeArgument {
|
|
so_far: 0,
|
|
__func__,
|
|
};
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[inline]
|
|
pub fn inc(&mut self, input: &[u8]) -> Result<(), CommandError> {
|
|
let Self::BeforeArgument { __func__, so_far } = *self else {
|
|
unreachable!(
|
|
"ArgCheck::inc called with invalid variant: {}",
|
|
if matches!(self, Self::Start { .. }) {
|
|
"Start"
|
|
} else {
|
|
"Eof"
|
|
}
|
|
);
|
|
};
|
|
let is_empty = input.trim().is_empty();
|
|
let new_value = so_far + 1;
|
|
if is_empty && new_value > MAX {
|
|
return Err(CommandError::WrongNumberOfArguments {
|
|
too_many: true,
|
|
takes: (MIN, MAX.into()),
|
|
given: new_value,
|
|
__func__,
|
|
inner: format!(
|
|
"needs {}{} arguments.",
|
|
if MIN == MAX { "at least " } else { "" },
|
|
MIN
|
|
)
|
|
.into(),
|
|
});
|
|
}
|
|
*self = Self::BeforeArgument {
|
|
so_far: new_value,
|
|
__func__,
|
|
};
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[inline]
|
|
pub fn finish(&mut self, input: &[u8]) -> Result<(), CommandError> {
|
|
let Self::BeforeArgument { __func__, so_far } = *self else {
|
|
unreachable!(
|
|
"ArgCheck::finish called with invalid variant: {}",
|
|
if matches!(self, Self::Start { .. }) {
|
|
"Start"
|
|
} else {
|
|
"Eof"
|
|
}
|
|
);
|
|
};
|
|
let is_empty = input.trim().is_empty();
|
|
if !is_empty {
|
|
assert!(so_far <= MAX);
|
|
assert!(so_far >= MIN);
|
|
return Err(CommandError::WrongNumberOfArguments {
|
|
too_many: true,
|
|
takes: (MIN, MAX.into()),
|
|
given: so_far + 1,
|
|
__func__,
|
|
inner: format!(
|
|
"needs {}{} arguments.",
|
|
if MIN == MAX { "at least " } else { "" },
|
|
MIN
|
|
)
|
|
.into(),
|
|
});
|
|
}
|
|
*self = Self::Eof { so_far, __func__ };
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
macro_rules! arg_init {
|
|
(min_arg: $n:expr, max_arg: $x:expr, $func:tt) => {{
|
|
ArgCheck::<$n, $x>::new(stringify!($func))
|
|
}};
|
|
}
|
|
|
|
//macro_rules! arg_value_check {
|
|
// ($tag:literal, $input:expr) => {{
|
|
// if tag::<&'_ str, &'_ [u8],
|
|
// melib::nom::error::Error<&[u8]>>($tag)($input).is_err() { return
|
|
// Ok(( $input,
|
|
// Err(CommandError::BadValue {
|
|
// inner: $tag.to_string().into(),
|
|
// }),
|
|
// ));
|
|
// }
|
|
// tag($tag)($input)
|
|
// }};
|
|
//}
|
|
|
|
macro_rules! arg_chk {
|
|
(start $check:ident, $input:expr) => {{
|
|
if let Err(err) = $check.start($input) {
|
|
return Ok(($input, Err(err)));
|
|
};
|
|
}};
|
|
(inc $check:ident, $input:expr) => {{
|
|
if let Err(err) = $check.inc($input) {
|
|
return Ok(($input, Err(err)));
|
|
};
|
|
}};
|
|
(finish $check:ident, $input:expr) => {{
|
|
if let Err(err) = $check.finish($input) {
|
|
return Ok(($input, Err(err)));
|
|
};
|
|
}};
|
|
}
|