1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
use std::{thread::sleep, time::Duration};

use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};

use crate::{Result, Table, Tool, ToolInfo, Value, ValueType, TOOL_LIST};

pub struct Help;

impl Tool for Help {
    fn info(&self) -> ToolInfo<'static> {
        ToolInfo {
            identifier: "help",
            description: "Get help using dust.",
            group: "general",
            inputs: vec![ValueType::Empty, ValueType::String],
        }
    }

    fn run(&self, argument: &Value) -> Result<Value> {
        self.check_type(argument)?;

        let mut table = Table::new(vec![
            "tool".to_string(),
            "description".to_string(),
            "group".to_string(),
            "inputs".to_string(),
        ]);

        for tool in TOOL_LIST {
            let tool_group = tool.info().group.to_string();

            if let Ok(group) = argument.as_string() {
                if &tool_group != group {
                    continue;
                }
            }

            let row = vec![
                Value::String(tool.info().identifier.to_string()),
                Value::String(tool.info().description.to_string()),
                Value::String(tool_group),
                Value::List(
                    tool.info()
                        .inputs
                        .iter()
                        .map(|value_type| Value::String(value_type.to_string()))
                        .collect(),
                ),
            ];

            table.insert(row)?;
        }

        Ok(Value::Table(table))
    }
}

pub struct Output;

impl Tool for Output {
    fn info(&self) -> ToolInfo<'static> {
        ToolInfo {
            identifier: "output",
            description: "Print a value.",
            group: "general",
            inputs: vec![ValueType::Any],
        }
    }

    fn run(&self, argument: &Value) -> Result<Value> {
        println!("{argument}");

        Ok(Value::Empty)
    }
}
pub struct Repeat;

impl Tool for Repeat {
    fn info(&self) -> ToolInfo<'static> {
        ToolInfo {
            identifier: "repeat",
            description: "Run a function the given number of times.",
            group: "general",
            inputs: vec![ValueType::ListExact(vec![
                ValueType::Function,
                ValueType::Integer,
            ])],
        }
    }

    fn run(&self, argument: &Value) -> Result<Value> {
        let argument = argument.as_list()?;
        let function = argument[0].as_function()?;
        let count = argument[1].as_int()?;
        let mut result_list = Vec::with_capacity(count as usize);

        for _ in 0..count {
            let result = function.run()?;

            result_list.push(result);
        }

        Ok(Value::List(result_list))
    }
}

pub struct Run;

impl Tool for Run {
    fn info(&self) -> ToolInfo<'static> {
        ToolInfo {
            identifier: "run",
            description: "Run functions in parallel.",
            group: "general",
            inputs: vec![ValueType::ListOf(Box::new(ValueType::Function))],
        }
    }

    fn run(&self, argument: &Value) -> Result<Value> {
        let argument_list = argument.as_list()?;
        let results = argument_list
            .par_iter()
            .map(|value| {
                let function = if let Ok(function) = value.as_function() {
                    function
                } else {
                    return value.clone();
                };

                match function.run() {
                    Ok(value) => value,
                    Err(error) => Value::String(error.to_string()),
                }
            })
            .collect();

        Ok(Value::List(results))
    }
}

pub struct Wait;

impl Tool for Wait {
    fn info(&self) -> crate::ToolInfo<'static> {
        ToolInfo {
            identifier: "wait",
            description: "Wait for the given number of milliseconds.",
            group: "general",
            inputs: vec![ValueType::Integer],
        }
    }

    fn run(&self, argument: &Value) -> Result<Value> {
        let argument = argument.as_int()?;

        sleep(Duration::from_millis(argument as u64));

        Ok(Value::Empty)
    }
}