首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将内部库Enum用于Clap

如何将内部库Enum用于Clap
EN

Stack Overflow用户
提问于 2020-06-20 20:50:28
回答 2查看 3K关注 0票数 4

我目前正在开发一个安全锈蚀口 工具。根据Rust的指南,我希望将核心库隔离到它自己的机箱中,这样我们就可以创建各种工具(CLI、API、streams等)。与核心库的接口,而不将它们耦合在一起。

核心库公开两个公共Enum,其中一个是PermutationMode (截断):

代码语言:javascript
复制
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum PermutationMode {
    All,
    Addition,
    BitSquatting,
    Homoglyph,
}

在使用鼓掌创建CLI实用程序时,我希望将此库Enum扩展为CLI的一部分,如下所示:

代码语言:javascript
复制
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需要知道内部模式(如果库添加了更多的模式)。

代码语言:javascript
复制
./twist-cli --registered-domains --permutation_mode=all example.com

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

代码语言:javascript
复制
#[derive(Clap)]
type ArgPermutationMode = PermutationMode

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

代码语言:javascript
复制
enum ArgPermutationMode {
    PermutationMode::All,
}

它不编译。

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-06-20 21:19:30

不幸的是没有。您必须重新定义枚举,以便arg_enum!宏可以访问令牌。

如果在两者之间添加一个转换函数,则可以确保对库枚举的上游更改强制您更新CLI,方法是提供一个编译错误:

代码语言:javascript
复制
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,
         }
    }
}

如果你发现自己经常这样做的话,你可以用宏减少样板。

考虑到您可以控制另一个板条箱,您可以通过尝试其他几个解决方案中的一个来妥协:

  • 在单独的文件中定义实际的枚举变体,并使用include!在两个板条箱中使用相同的源。这假设您的板条箱在同一个工作区中。
  • 使用宏派生,如EnumIter,来自strum_macros。这将使您可以迭代枚举的变体,这样您就可以将它们提供给Clap,而不必在这个板条箱中有can依赖关系。相反,您将有一个strum_macros依赖项,所以这取决于您是否真的更好。
  • 在内部机箱中添加clap_args!调用,但功能门。您的应用程序机箱可以启用此功能,但大多数用户不会。
票数 5
EN

Stack Overflow用户

发布于 2020-06-23 16:50:08

这是对上述答案的扩展,以防对其他人有帮助。最终,我选择在库中实现FromStr,如下所示:

代码语言:javascript
复制
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传递到置换模式之一。

代码语言:javascript
复制
let permutation_mode = matches
    .value_of("permutation_mode")
    .unwrap()
    .parse::<PermutationMode>()
    .unwrap();

这样,我们不需要将客户端和库之间的模式耦合起来,并且总体上使示例CLI更具可塑性。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62491508

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档