/* * 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 . */ //! Helper type for showing the exact reason why a command was invalid. use super::*; pub enum ArgCheck { Start { __func__: &'static str }, BeforeArgument { so_far: u8, __func__: &'static str }, Eof { so_far: u8, __func__: &'static str }, } impl ArgCheck { #[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))); }; }}; }