/* * Copyright (c) 2023 Emma Tebibyte * SPDX-License-Identifier: LGPL-3.0-or-later * * This file is part of SPD. * * SPD is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * SPD 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with SPD. If not, see . * * This file incorporates work covered by the following copyright and permission * notice: * * Copyright 2017 Douman * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #![no_std] #![warn(missing_docs)] #![cfg_attr(feature = "cargo-clippy", allow(clippy::style))] #![cfg_attr(feature = "cargo-clippy", allow(clippy::needless_lifetimes))] use core::fmt; mod derive; mod split; use derive::*; use split::Split; #[derive(PartialEq, Eq, Debug)] ///Parse errors pub enum ParseKind<'a> { ///Main command result Top(ParseError<'a>), ///Sub-command name and result Sub(&'static str, ParseError<'a>), } impl<'a> ParseKind<'a> { #[inline] ///Returns whether help is requested pub fn is_help(&self) -> bool { match self { Self::Top(err) => err.is_help(), Self::Sub(_, err) => err.is_help(), } } } impl<'a> PartialEq> for ParseKind<'a> { #[inline(always)] fn eq(&self, right: &ParseError<'a>) -> bool { match self { Self::Top(left) => PartialEq::eq(left, right), Self::Sub(_, left) => PartialEq::eq(left, right), } } } #[derive(PartialEq, Eq, Debug)] ///Parse errors pub enum ParseError<'a> { ///User requested help. /// ///Contains slice with `Args::HELP` HelpRequested(&'static str), ///Too many arguments are specified. TooManyArgs, ///Argument is required, but missing /// ///Contains name of argument RequiredArgMissing(&'a str), ///Flag is specified, but value is missing. /// ///Contains full flag name. MissingValue(&'a str), ///Flag is specified with invalid value /// ///Contains full flag name and provided value. InvalidFlagValue(&'a str, &'a str), ///Argument is supplied with invalid vlaue /// ///Contains argument name and provided value. InvalidArgValue(&'a str, &'a str), ///Unknown flag is specified. UnknownFlag(&'a str) } impl<'a> ParseError<'a> { ///Returns whether help is requested pub fn is_help(&self) -> bool { match self { ParseError::HelpRequested(_) => true, _ => false, } } } impl<'a> fmt::Display for ParseError<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ParseError::HelpRequested(help) => f.write_str(help), ParseError::TooManyArgs => f.write_str("Too many arguments are provided"), ParseError::RequiredArgMissing(arg) => write!(f, "Argument '{}' is required, but not provided", arg), ParseError::MissingValue(arg) => write!(f, "Flag '{}' is provided without value", arg), ParseError::InvalidFlagValue(arg, value) => write!(f, "Flag '{}' is provided with '{}' which is invalid", arg, value), ParseError::InvalidArgValue(arg, value) => write!(f, "Argument '{}' is provided with '{}' which is invalid", arg, value), ParseError::UnknownFlag(flag) => write!(f, "Unknown flag '{}' is provided", flag), } } } impl<'a> fmt::Display for ParseKind<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ParseKind::Top(res) => fmt::Display::fmt(res, f), ParseKind::Sub(name, res) => write!(f, "{name}: {res}"), } } } ///Describers command line argument parser pub trait Args: Sized { ///Help message for parser. const HELP: &'static str; ///Parses arguments from iterator of strings fn from_args<'a, T: IntoIterator>(args: T) -> Result>; ///Parses arguments from string, which gets tokenized and passed to from. fn from_text<'a>(text: &'a str) -> Result> { Self::from_args(Split::from_str(text)) } }