#arguments-parser #derive #subcommand #optimized #size #enums #argp

argp_derive

基于派生的参数解析,针对代码大小优化

3个版本 (破坏性)

0.3.0 2023年4月19日
0.2.0 2023年3月26日
0.1.0 2023年2月7日

#86 in #optimized

Download history 120/week @ 2024-03-14 63/week @ 2024-03-21 134/week @ 2024-03-28 41/week @ 2024-04-04 57/week @ 2024-04-11 79/week @ 2024-04-18 176/week @ 2024-04-25 56/week @ 2024-05-02 128/week @ 2024-05-09 529/week @ 2024-05-16 75/week @ 2024-05-23 185/week @ 2024-05-30 205/week @ 2024-06-06 208/week @ 2024-06-13 141/week @ 2024-06-20 65/week @ 2024-06-27

每月645次下载
5个crate中使用(通过argp

BSD-3-Clause

88KB
2K SLoC

Argp是一个基于派生的参数解析器,针对代码大小和灵活性进行优化。

该库的公共API主要由FromArgs派生和parse_args_or_exit函数组成,可以使用它们从当前程序的命令行参数生成顶级FromArgs类型。

特性

  • 无运行时依赖。

  • 小尺寸开销 - ~40 kiB [1],这是比clapclap_derive10倍!有关更多详细信息,请参阅argparse-rosetta-rs

  • 基于派生的API - 您定义用于解析值的结构和枚举,使用属性指定如何解析,过程派生宏将在编译时生成解析器。

  • 上下文敏感解析。

  • 支持子命令。

  • 带有Markdown支持的帮助信息生成器,以及基于终端宽度的动态换行。

起源

Argp最初是argh的一个分支,目的是使其更具UNIX风格、更灵活。

与argh的显著变化

  • 支持全局选项(即顶层定义的选项可以在子命令中使用)。

  • 支持组合短选项(例如,-ab被解析为-a -b-an 5被解析为-a -n 5)。

  • 支持非UTF8参数(OsStr)。

  • from_str_fn属性还可以包含函数路径,而不仅仅是单个标识符,并且可以返回任何实现了ToStringErr类型。

  • 对描述以小写字母开头没有严格的限制。

  • 帮助信息根据终端宽度动态包装(在Unix系统上)。

  • 帮助信息中描述的缩进是根据所有元素的宽度动态计算的。

  • 即使在位置参数上,也可以使用 arg_name 属性来自定义在帮助信息中显示参数的方式。

  • 错误使用枚举而不是字符串来表示,生成帮助信息所使用的信息以部分结构化的形式存储在结构体中;这为消息的定制打开了大门。

  • 将专门的 examplenoteerror_code 属性替换为单个 footer 属性——您可以用它来做任何事情。

  • 在用法字符串中的位置参数显示在选项和开关之后,并且在选项描述中使用 <arg_name> 显示。

  • -h, --help 开关之后允许出现尾随选项,但只允许在 help 子命令之后。

  • from_env 函数重命名为 parse_args_or_exitcargo_from_env 重命名为 cargo_parse_args_or_exit

  • redact_arg_values 已被移除(如果您需要它,请在问题中告诉我)。

基本示例

use argp::FromArgs;

/// Reach new heights.
#[derive(FromArgs)]
struct GoUp {
    /// Whether or not to jump.
    #[argp(switch, short = 'j')]
    jump: bool,

    /// How high to go.
    #[argp(option, arg_name = "meters")]
    height: usize,

    /// An optional nickname for the pilot.
    #[argp(option, arg_name = "name")]
    pilot_nickname: Option<String>,
}

fn main() {
    let up: GoUp = argp::parse_args_or_exit(argp::DEFAULT);
}

./some_bin --help 将输出以下内容

Usage: cmdname [-j] --height <meters> [--pilot-nickname <name>]

Reach new heights.

Options:
  -j, --jump                   Whether or not to jump.
      --height <meters>        How high to go.
      --pilot-nickname <name>  An optional nickname for the pilot.
  -h, --help                   Show this help message and exit.

生成的程序可以用以下任何一种方式使用

  • ./some_bin --height 5

  • ./some_bin -j --height 5

  • ./some_bin --jump --height 5 --pilot-nicknameWes

开关,如 jump,是可选的,如果提供,则设置为 true。

选项,如 heightpilot_nickname,可以是必需的、可选的或重复的,具体取决于它们是否包含在 OptionVec 中。可以使用 #[argp(default = "<your_code_here>")] 属性提供默认值,在这种情况下,选项被视为可选的。

use argp::FromArgs;

fn default_height() -> usize {
    5
}

/// Reach new heights.
#[derive(FromArgs)]
struct GoUp {
    /// An optional nickname for the pilot.
    #[argp(option)]
    pilot_nickname: Option<String>,

    /// An optional height.
    #[argp(option, default = "default_height()")]
    height: usize,

    /// An optional direction which is "up" by default.
    #[argp(option, default = "String::from(\"only up\")")]
    direction: String,
}

fn main() {
    let up: GoUp = argp::parse_args_or_exit(argp::DEFAULT);
}

只要实现 FromArgValue 特性(已经为在 std 中实现 FromStr 特性的大多数类型实现),就可以反序列化自定义选项类型。如果需要更多的自定义解析,可以使用 from_str_fn 属性提供一个自定义 fn(&str)Result<T, E>,或者使用 from_os_str_fn 属性提供一个自定义 fn(&OsStr)Result<T, E>,其中 E 实现 ToString

use argp::FromArgs;
use std::ffi::OsStr;
use std::path::PathBuf;

/// Goofy thing.
#[derive(FromArgs)]
struct FineStruct {
    /// Always five.
    #[argp(option, from_str_fn(always_five))]
    five: usize,

    /// File path.
    #[argp(option, from_os_str_fn(convert_path))]
    path: PathBuf,
}

fn always_five(_value: &str) -> Result<usize, String> {
    Ok(5)
}

fn convert_path(value: &OsStr) -> Result<PathBuf, String> {
    Ok(PathBuf::from("/tmp").join(value))
}

可以使用 #[argp(positional)] 来声明位置参数。这些参数将按照结构体中声明的顺序进行解析。

use argp::FromArgs;

/// A command with positional arguments.
#[derive(FromArgs, PartialEq, Debug)]
struct WithPositional {
    #[argp(positional)]
    first: String,
}

最后一个位置参数可以包含默认值,或者用 OptionVec 包装,以表示可选或重复的位置参数。

也支持子命令。要使用子命令,为每个子命令声明一个单独的 FromArgs 类型,以及一个遍历每个命令的枚举。

use argp::FromArgs;

/// Top-level command.
#[derive(FromArgs, PartialEq, Debug)]
struct TopLevel {
    /// Be verbose.
    #[argp(switch, short = 'v', global)]
    verbose: bool,

    #[argp(subcommand)]
    nested: MySubCommandEnum,
}

#[derive(FromArgs, PartialEq, Debug)]
#[argp(subcommand)]
enum MySubCommandEnum {
    One(SubCommandOne),
    Two(SubCommandTwo),
}

/// First subcommand.
#[derive(FromArgs, PartialEq, Debug)]
#[argp(subcommand, name = "one")]
struct SubCommandOne {
    /// How many x.
    #[argp(option)]
    x: usize,
}

/// Second subcommand.
#[derive(FromArgs, PartialEq, Debug)]
#[argp(subcommand, name = "two")]
struct SubCommandTwo {
    /// Whether to fooey.
    #[argp(switch)]
    fooey: bool,
}

有关更多信息,请参阅 argp 文档

如何调试 argp 的展开 derive 宏

可以使用 cargo-expand crate 调试 argp::FromArgs derive 宏。

examples/simple_example.rs 中展开 derive 宏

请参阅 argp/examples/simple_example.rs,以了解我们希望展开的示例结构体。

首先,通过运行 cargo install cargo-expand 来安装 cargo-expand。注意,这需要 Rust 的夜间构建。

安装完成后,在 argp 包中运行 cargo expand,您可以看到展开的代码。

许可证

本项目采用 BSD-3-Clause 许可证。有关许可证的全文,请参阅 LICENSE 文件。

  1. 在带有 strip = truepanic = "abort" 的发布构建中进行了测量。确切的大小取决于多个因素,包括选项和子命令的数量。

依赖关系

~3MB
~59K SLoC