use std::io::{self, Write};
use byte_unit::Byte;
use clap::{Command, CommandFactory, Parser, ValueEnum};
use clap_complete::Generator;
#[derive(Debug, Parser)]
#[command(version, about, max_term_width(100))]
pub struct Opt {
#[arg(short, long, value_enum, default_value_t, ignore_case(true))]
pub format: Format,
#[arg(
short,
long,
value_enum,
default_value_t,
value_name("RNG"),
ignore_case(true)
)]
pub random_number_generator: Rng,
#[arg(short, long, value_name("NUMBER"))]
pub seed: Option<u64>,
#[arg(short, long)]
pub progress: bool,
#[arg(long, value_enum, value_name("SHELL"))]
pub generate_completion: Option<Shell>,
#[arg(required_unless_present("generate_completion"))]
pub bytes: Option<Byte>,
}
impl Opt {
pub fn print_completion(generator: impl Generator) {
clap_complete::generate(
generator,
&mut Self::command(),
Self::command().get_name(),
&mut io::stdout(),
);
}
}
#[derive(Clone, Debug, ValueEnum)]
#[allow(clippy::doc_markdown)]
#[value(rename_all = "lower")]
pub enum Shell {
Bash,
Elvish,
Fish,
Nushell,
#[allow(clippy::enum_variant_names)]
PowerShell,
Zsh,
}
impl Generator for Shell {
fn file_name(&self, name: &str) -> String {
match self {
Self::Bash => clap_complete::Shell::Bash.file_name(name),
Self::Elvish => clap_complete::Shell::Elvish.file_name(name),
Self::Fish => clap_complete::Shell::Fish.file_name(name),
Self::Nushell => clap_complete_nushell::Nushell.file_name(name),
Self::PowerShell => clap_complete::Shell::PowerShell.file_name(name),
Self::Zsh => clap_complete::Shell::Zsh.file_name(name),
}
}
fn generate(&self, cmd: &Command, buf: &mut dyn Write) {
match self {
Self::Bash => clap_complete::Shell::Bash.generate(cmd, buf),
Self::Elvish => clap_complete::Shell::Elvish.generate(cmd, buf),
Self::Fish => clap_complete::Shell::Fish.generate(cmd, buf),
Self::Nushell => clap_complete_nushell::Nushell.generate(cmd, buf),
Self::PowerShell => clap_complete::Shell::PowerShell.generate(cmd, buf),
Self::Zsh => clap_complete::Shell::Zsh.generate(cmd, buf),
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, ValueEnum)]
#[value(rename_all = "lower")]
pub enum Format {
#[default]
Raw,
#[cfg(feature = "base64")]
Base64,
#[cfg(feature = "base64")]
Base64Url,
#[cfg(feature = "hex")]
Hex,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, ValueEnum)]
#[allow(clippy::doc_markdown)]
#[value(rename_all = "lower")]
pub enum Rng {
ChaCha8,
#[default]
ChaCha12,
ChaCha20,
#[cfg(feature = "hc")]
Hc128,
#[cfg(feature = "isaac")]
Isaac,
#[cfg(feature = "isaac")]
Isaac64,
#[cfg(feature = "mt")]
Mt,
#[cfg(feature = "mt")]
Mt64,
#[cfg(feature = "pcg")]
Pcg32,
#[cfg(feature = "pcg")]
Pcg64,
#[cfg(feature = "pcg")]
Pcg64Dxsm,
#[cfg(feature = "pcg")]
Pcg64Mcg,
#[cfg(feature = "sfc")]
Sfc32,
#[cfg(feature = "sfc")]
Sfc64,
SplitMix64,
#[cfg(feature = "xorshift")]
XorShift,
#[value(name = "xoroshiro64*")]
Xoroshiro64Star,
#[value(name = "xoroshiro64**")]
Xoroshiro64StarStar,
#[value(name = "xoroshiro128+")]
Xoroshiro128Plus,
#[value(name = "xoroshiro128++")]
Xoroshiro128PlusPlus,
#[value(name = "xoroshiro128**")]
Xoroshiro128StarStar,
#[value(name = "xoshiro128+")]
Xoshiro128Plus,
#[value(name = "xoshiro128++")]
Xoshiro128PlusPlus,
#[value(name = "xoshiro128**")]
Xoshiro128StarStar,
#[value(name = "xoshiro256+")]
Xoshiro256Plus,
#[value(name = "xoshiro256++")]
Xoshiro256PlusPlus,
#[value(name = "xoshiro256**")]
Xoshiro256StarStar,
#[value(name = "xoshiro512+")]
Xoshiro512Plus,
#[value(name = "xoshiro512++")]
Xoshiro512PlusPlus,
#[value(name = "xoshiro512**")]
Xoshiro512StarStar,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verify_app() {
Opt::command().debug_assert();
}
#[test]
fn file_name_shell() {
assert_eq!(Shell::Bash.file_name("randgen"), "randgen.bash");
assert_eq!(Shell::Elvish.file_name("randgen"), "randgen.elv");
assert_eq!(Shell::Fish.file_name("randgen"), "randgen.fish");
assert_eq!(Shell::Nushell.file_name("randgen"), "randgen.nu");
assert_eq!(Shell::PowerShell.file_name("randgen"), "_randgen.ps1");
assert_eq!(Shell::Zsh.file_name("randgen"), "_randgen");
}
#[test]
fn default_format() {
assert_eq!(Format::default(), Format::Raw);
}
#[test]
fn default_rng() {
assert_eq!(Rng::default(), Rng::ChaCha12);
}
}