nu_command/random/
chars.rs1use super::byte_stream::{RandomDistribution, random_byte_stream};
2use nu_engine::command_prelude::*;
3
4const DEFAULT_CHARS_LENGTH: usize = 25;
5
6#[derive(Clone)]
7pub struct RandomChars;
8
9impl Command for RandomChars {
10 fn name(&self) -> &str {
11 "random chars"
12 }
13
14 fn signature(&self) -> Signature {
15 Signature::build("random chars")
16 .input_output_types(vec![(Type::Nothing, Type::String)])
17 .allow_variants_without_examples(true)
18 .named(
19 "length",
20 SyntaxShape::OneOf(vec![SyntaxShape::Int, SyntaxShape::Filesize]),
21 "Number of chars (default 25)",
22 Some('l'),
23 )
24 .category(Category::Random)
25 }
26
27 fn description(&self) -> &str {
28 "Generate random chars uniformly distributed over ASCII letters and numbers: a-z, A-Z and 0-9."
29 }
30
31 fn search_terms(&self) -> Vec<&str> {
32 vec!["generate", "character", "symbol", "alphanumeric"]
33 }
34
35 fn run(
36 &self,
37 engine_state: &EngineState,
38 stack: &mut Stack,
39 call: &Call,
40 _input: PipelineData,
41 ) -> Result<PipelineData, ShellError> {
42 chars(engine_state, stack, call)
43 }
44
45 fn examples(&self) -> Vec<Example> {
46 vec![
47 Example {
48 description: "Generate a string with 25 random chars",
49 example: "random chars",
50 result: None,
51 },
52 Example {
53 description: "Generate random chars with specified length",
54 example: "random chars --length 20",
55 result: None,
56 },
57 Example {
58 description: "Generate one kilobyte of random chars",
59 example: "random chars --length 1kb",
60 result: None,
61 },
62 ]
63 }
64}
65
66fn chars(
67 engine_state: &EngineState,
68 stack: &mut Stack,
69 call: &Call,
70) -> Result<PipelineData, ShellError> {
71 let length: Option<Value> = call.get_flag(engine_state, stack, "length")?;
72 let length = if let Some(length_val) = length {
73 match length_val {
74 Value::Int { val, .. } => usize::try_from(val).map_err(|_| ShellError::InvalidValue {
75 valid: "a non-negative int or filesize".into(),
76 actual: val.to_string(),
77 span: length_val.span(),
78 }),
79 Value::Filesize { val, .. } => {
80 usize::try_from(val).map_err(|_| ShellError::InvalidValue {
81 valid: "a non-negative int or filesize".into(),
82 actual: engine_state.get_config().filesize.format(val).to_string(),
83 span: length_val.span(),
84 })
85 }
86 val => Err(ShellError::RuntimeTypeMismatch {
87 expected: Type::custom("int or filesize"),
88 actual: val.get_type(),
89 span: val.span(),
90 }),
91 }?
92 } else {
93 DEFAULT_CHARS_LENGTH
94 };
95
96 Ok(random_byte_stream(
97 RandomDistribution::Alphanumeric,
98 length,
99 call.head,
100 engine_state.signals().clone(),
101 ))
102}
103
104#[cfg(test)]
105mod test {
106 use super::*;
107
108 #[test]
109 fn test_examples() {
110 use crate::test_examples;
111
112 test_examples(RandomChars {})
113 }
114}