nu_command/random/
dice.rs1use 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}