158 lines
5.0 KiB
Rust
158 lines
5.0 KiB
Rust
/*
|
|
* Copyright (c) 2023 Emma Tebibyte <emma@tebibyte.media>
|
|
* 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 <https://www.gnu.org/licenses/>.
|
|
*
|
|
* 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<ParseError<'a>> 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<Item = &'a str>>(args: T) -> Result<Self, ParseKind<'a>>;
|
|
|
|
///Parses arguments from string, which gets tokenized and passed to from.
|
|
fn from_text<'a>(text: &'a str) -> Result<Self, ParseKind<'a>> {
|
|
Self::from_args(Split::from_str(text))
|
|
}
|
|
}
|