如何使用内部库 Enum 进行 Clap Args

问题描述 投票:0回答:2

我目前正在开发安全工具Rust 端口。与 Rust 的指南一致,我想将核心库隔离到自己的包中,以便我们可以创建与核心库交互的各种工具(CLI、API、流等),而无需将它们耦合在一起。

核心库公开了两个公共枚举,其中之一是

PermutationMode
(已截断):

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum PermutationMode {
    All,
    Addition,
    BitSquatting,
    Homoglyph,
}

使用 Clap 创建 CLI 实用程序时,我想将此库 Enum 扩展为 CLI 的一部分,如下所示:

use clap::Clap;

use twistrs::permutate::PermutationMode;

#[derive(Clap, PartialEq, Debug)]
#[clap(name = "twistrs-cli")]
struct Opts {
    #[clap(short, long)]
    registered_domains: bool,

    #[clap(arg_enum)]
    permutation_mode: PermutationMode,
}

因此,在调用 CLI 时,我们可以将排列模式从用户无缝传递到 CLI、库,并且 CLI 无需了解内部模式(如果库添加了更多模式)。

./twist-cli --registered-domains --permutation_mode=all example.com

目前这似乎不可能(这是有道理的)。一种尝试是使用类型别名:

#[derive(Clap)]
type ArgPermutationMode = PermutationMode

但是我们不能将派生宏用于类型别名。我还尝试“克隆”枚举并尝试映射到库枚举:

enum ArgPermutationMode {
    PermutationMode::All,
}

无法编译。


问题 - 是否可以扩展内部库枚举以将其用作 Clap 参数?

rust clap
2个回答
10
投票

感谢@HamzaZubair;截至 24 年 10 月 1 日,使用 clap 的

ValueEnum
似乎是实现此行为的更合适方法。


这更多的是对上述答案的扩展,以防它对其他人有帮助。最终我最终选择的是在库中实现 implementing

FromStr
,如下所示:

impl FromStr for PermutationMode {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_ascii_lowercase().as_str() {
            "all" => Ok(PermutationMode::All),
            "addition" => Ok(PermutationMode::Addition),
            "bitsquatting" => Ok(PermutationMode::BitSquatting),
            "homoglyph" => Ok(PermutationMode::Homoglyph),
            _ => Err(),
        }
    }
}

为了避免客户端担心这些模式,我们只需尝试将通过 CLI 传递的字符串解析为其中一种排列模式。

let permutation_mode = matches .value_of("permutation_mode") .unwrap() .parse::<PermutationMode>() .unwrap();
这样我们就不需要耦合客户端和库之间的模式,总体上使示例 CLI 更具可延展性。


6
投票
不幸的是没有。您必须重新定义枚举,以便

arg_enum!

 宏可以访问标记。

如果您在两者之间添加转换函数,那么您可以确保对库枚举的上游更改会强制您更新 CLI,并给出编译错误:

arg_enum! { enum ArgPermutationMode { All, Addition, BitSquatting, Homoglyph, } } impl From<ArgPermutationMode> for PermutationMode { fn from(other: ArgPermutationMode) -> PermutationMode { match other { ArgPermutationMode::All => PermutationMode::All, ArgPermutationMode::Addition => PermutationMode::Addition, ArgPermutationMode::BitSquatting => PermutationMode::BitSquatting, ArgPermutationMode::Homoglyph => PermutationMode::Homoglyph, } } } impl From<PermutationMode> for ArgPermutationMode { fn from(other: PermutationMode) -> ArgPermutationMode { match other { PermutationMode::All => ArgPermutationMode::All, PermutationMode::Addition => ArgPermutationMode::Addition, PermutationMode::BitSquatting => ArgPermutationMode::BitSquatting, xPermutationMode::Homoglyph => ArgPermutationMode::Homoglyph, } } }
如果您发现自己经常这样做,可以使用宏来减少样板文件。


鉴于您可以控制另一个板条箱,您可以通过尝试其他几种解决方法之一来妥协:

© www.soinside.com 2019 - 2024. All rights reserved.