nu_command/random/
dice.rs

1use nu_engine::command_prelude::*;
2use nu_protocol::{DeprecationEntry, DeprecationType, ListStream, ReportMode};
3use rand::random_range;
4use std::num::NonZeroUsize;
5
6#[derive(Clone)]
7pub struct RandomDice;
8
9impl Command for RandomDice {
10    fn name(&self) -> &str {
11        "random dice"
12    }
13
14    fn signature(&self) -> Signature {
15        Signature::build("random dice")
16            .input_output_types(vec![(Type::Nothing, Type::list(Type::Int))])
17            .allow_variants_without_examples(true)
18            .named(
19                "dice",
20                SyntaxShape::Int,
21                "The amount of dice being rolled",
22                Some('d'),
23            )
24            .named(
25                "sides",
26                SyntaxShape::Int,
27                "The amount of sides a die has",
28                Some('s'),
29            )
30            .category(Category::Random)
31    }
32
33    fn description(&self) -> &str {
34        "Generate a random dice roll."
35    }
36
37    fn search_terms(&self) -> Vec<&str> {
38        vec!["generate", "die", "1-6"]
39    }
40
41    fn deprecation_info(&self) -> Vec<DeprecationEntry> {
42        vec![DeprecationEntry {
43            ty: DeprecationType::Command,
44            report_mode: ReportMode::FirstUse,
45            since: Some("0.107.0".to_owned()),
46            expected_removal: Some("0.108.0".to_owned()),
47            help: Some("Use `random dice` from std/random instead.".to_owned()),
48        }]
49    }
50
51    fn run(
52        &self,
53        engine_state: &EngineState,
54        stack: &mut Stack,
55        call: &Call,
56        _input: PipelineData,
57    ) -> Result<PipelineData, ShellError> {
58        dice(engine_state, stack, call)
59    }
60
61    fn examples(&self) -> Vec<Example> {
62        vec![
63            Example {
64                description: "Roll 1 dice with 6 sides each",
65                example: "random dice",
66                result: None,
67            },
68            Example {
69                description: "Roll 10 dice with 12 sides each",
70                example: "random dice --dice 10 --sides 12",
71                result: None,
72            },
73        ]
74    }
75}
76
77fn dice(
78    engine_state: &EngineState,
79    stack: &mut Stack,
80    call: &Call,
81) -> Result<PipelineData, ShellError> {
82    let span = call.head;
83
84    let sides: NonZeroUsize = call
85        .get_flag(engine_state, stack, "sides")?
86        .unwrap_or_else(|| NonZeroUsize::new(6).expect("default sides must be non-zero"));
87
88    let dice: NonZeroUsize = call
89        .get_flag(engine_state, stack, "dice")?
90        .unwrap_or_else(|| NonZeroUsize::new(1).expect("default dice count must be non-zero"));
91
92    let sides = sides.get();
93    let dice = dice.get();
94
95    let iter = (0..dice).map(move |_| Value::int(random_range(1..sides + 1) as i64, span));
96
97    Ok(ListStream::new(iter, span, engine_state.signals().clone()).into())
98}
99
100#[cfg(test)]
101mod test {
102    use super::*;
103
104    #[test]
105    fn test_examples() {
106        use crate::test_examples;
107
108        test_examples(RandomDice {})
109    }
110}