我目前正在开发一个安全工具的Rust 端口。根据 Rust 的指南,我想将核心库隔离到自己的包中,以便我们可以创建与核心库交互的各种工具(CLI、API、流等),而无需将它们耦合在一起。
核心库公开了两个公共枚举,其中之一是PermutationMode(截断的):
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum PermutationMode {
All,
Addition,
BitSquatting,
Homoglyph,
}
Run Code Online (Sandbox Code Playgroud)
使用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,
}
Run Code Online (Sandbox Code Playgroud)
这样,在调用 CLI 时,我们可以将排列模式从用户无缝传递到 CLI、库,并且 CLI 无需了解内部模式(如果库添加了更多模式)。
./twist-cli --registered-domains --permutation_mode=all example.com
Run Code Online (Sandbox Code Playgroud)
目前这似乎不可能(这是有道理的)。一种尝试是使用类型别名:
./twist-cli --registered-domains --permutation_mode=all example.com
Run Code Online (Sandbox Code Playgroud)
但是,我们不能将派生宏用于类型别名。我还尝试“克隆”枚举并尝试映射到库枚举:
#[derive(Clap)]
type ArgPermutationMode = PermutationMode
Run Code Online (Sandbox Code Playgroud)
哪个不编译。
问题- 是否可以扩展内部库 Enum 以将其用作 Clap 参数?
Jux*_*hin 11
感谢@HamzaZubair;截至 24 年 10 月 1 日,使用 clap 似乎ValueEnum是实现此行为的更合适的方法。
这更多的是对上述答案的扩展,以防它可能对其他人有所帮助。最终我最终选择在库中实现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(),
}
}
}
Run Code Online (Sandbox Code Playgroud)
为了避免客户端担心这些模式,我们只需尝试将通过 CLI 传递的字符串解析为其中一种排列模式。
let permutation_mode = matches
.value_of("permutation_mode")
.unwrap()
.parse::<PermutationMode>()
.unwrap();
Run Code Online (Sandbox Code Playgroud)
这样我们就不需要耦合客户端和库之间的模式,总体上使示例 CLI 更具可塑性。
不幸的是没有。您必须重新定义枚举,以便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,
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果您发现自己经常这样做,则可以使用宏来减少样板文件。
鉴于您可以控制另一个箱子,您可以通过尝试其他几种解决方法之一来妥协:
include!在两个包中使用相同的源。这假设您的板条箱位于同一工作空间中。EnumIter使用类似from的宏派生strum_macros。这将允许您迭代枚举的变体,以便您可以将它们提供给 Clap,而无需在该板条箱中具有 Clap 依赖项。相反,您将产生strum_macros依赖关系,因此这是否真的更好取决于您。clap_args!到内部包中,但对其进行功能门控。您的应用程序箱可以启用此功能,但大多数用户不会。| 归档时间: |
|
| 查看次数: |
8557 次 |
| 最近记录: |