Skip to content

Commit c008157

Browse files
authored
Merge pull request #54 from rust-lang/optional-args
Add support for optional arguments
2 parents 60eb4c6 + 3996663 commit c008157

File tree

2 files changed

+139
-91
lines changed

2 files changed

+139
-91
lines changed

src/commands.rs

Lines changed: 112 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::state_machine::{CharacterSet, StateMachine};
22
use reqwest::blocking::Client as HttpClient;
33
use serenity::{model::channel::Message, prelude::Context};
4-
use std::collections::HashMap;
4+
use std::{collections::HashMap, sync::Arc};
55

66
const PREFIX: &'static str = "?";
77
pub(crate) type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
8-
pub(crate) type CmdPtr = Box<dyn for<'m> Fn(Args<'m>) -> Result<()> + Send + Sync>;
8+
pub(crate) type CmdPtr = Arc<dyn for<'m> Fn(Args<'m>) -> Result<()> + Send + Sync>;
99

1010
pub struct Args<'m> {
1111
pub http: &'m HttpClient,
@@ -35,45 +35,72 @@ impl Commands {
3535
handler: impl Fn(Args) -> Result<()> + Send + Sync + 'static,
3636
) {
3737
info!("Adding command {}", &command);
38-
let mut param_names = Vec::new();
3938
let mut state = 0;
4039

40+
let mut opt_lambda_state = None;
41+
let mut opt_final_states = vec![];
42+
4143
command
4244
.split(' ')
4345
.filter(|segment| segment.len() > 0)
4446
.enumerate()
4547
.for_each(|(i, segment)| {
46-
if segment.starts_with("```\n") && segment.ends_with("```") {
47-
state = add_space(&mut self.state_machine, state, i);
48-
state = add_code_segment_multi_line(&mut self.state_machine, state);
49-
param_names.push(&segment[4..segment.len() - 3]);
50-
} else if segment.starts_with("```") && segment.ends_with("```") {
51-
state = add_space(&mut self.state_machine, state, i);
52-
state = add_code_segment_single_line_long(&mut self.state_machine, state);
53-
param_names.push(&segment[3..segment.len() - 3]);
54-
} else if segment.starts_with("`") && segment.ends_with("`") {
55-
state = add_space(&mut self.state_machine, state, i);
56-
state = add_code_segment_single_line_short(&mut self.state_machine, state);
57-
param_names.push(&segment[1..segment.len() - 1]);
58-
} else if segment.starts_with("{") && segment.ends_with("}") {
59-
state = add_space(&mut self.state_machine, state, i);
60-
state = add_dynamic_segment(&mut self.state_machine, state);
61-
param_names.push(&segment[1..segment.len() - 1]);
62-
} else if segment.ends_with("...") {
63-
state = add_space(&mut self.state_machine, state, i);
64-
state = add_remaining_segment(&mut self.state_machine, state);
65-
param_names.push(&segment[..segment.len() - 3]);
48+
if let Some(name) = key_value_pair(segment) {
49+
if let Some(lambda) = opt_lambda_state {
50+
state = add_key_value(&mut self.state_machine, name, lambda);
51+
self.state_machine.add_next_state(state, lambda);
52+
opt_final_states.push(state);
53+
} else {
54+
opt_final_states.push(state);
55+
state = add_space(&mut self.state_machine, state, i);
56+
opt_lambda_state = Some(state);
57+
state = add_key_value(&mut self.state_machine, name, state);
58+
self.state_machine
59+
.add_next_state(state, opt_lambda_state.unwrap());
60+
opt_final_states.push(state);
61+
}
6662
} else {
63+
opt_lambda_state = None;
64+
opt_final_states.truncate(0);
6765
state = add_space(&mut self.state_machine, state, i);
68-
segment.chars().for_each(|ch| {
69-
state = self.state_machine.add(state, CharacterSet::from_char(ch))
70-
});
66+
67+
if segment.starts_with("```\n") && segment.ends_with("```") {
68+
let name = &segment[4..segment.len() - 3];
69+
state = add_code_segment_multi_line(&mut self.state_machine, name, state);
70+
} else if segment.starts_with("```") && segment.ends_with("```") {
71+
let name = &segment[3..segment.len() - 3];
72+
state =
73+
add_code_segment_single_line(&mut self.state_machine, name, state, 3);
74+
} else if segment.starts_with("`") && segment.ends_with("`") {
75+
let name = &segment[1..segment.len() - 1];
76+
state =
77+
add_code_segment_single_line(&mut self.state_machine, name, state, 1);
78+
} else if segment.starts_with("{") && segment.ends_with("}") {
79+
let name = &segment[1..segment.len() - 1];
80+
state = add_dynamic_segment(&mut self.state_machine, name, state);
81+
} else if segment.ends_with("...") {
82+
let name = &segment[..segment.len() - 3];
83+
state = add_remaining_segment(&mut self.state_machine, name, state);
84+
} else {
85+
segment.chars().for_each(|ch| {
86+
state = self.state_machine.add(state, CharacterSet::from_char(ch))
87+
});
88+
}
7189
}
7290
});
7391

74-
self.state_machine.set_final_state(state);
75-
self.state_machine.set_handler(state, Box::new(handler));
76-
self.state_machine.set_param_names(state, param_names);
92+
let handler = Arc::new(handler);
93+
94+
if opt_lambda_state.is_some() {
95+
opt_final_states.iter().for_each(|state| {
96+
self.state_machine.set_final_state(*state);
97+
self.state_machine.set_handler(*state, handler.clone());
98+
});
99+
} else {
100+
self.state_machine.set_final_state(state);
101+
self.state_machine.set_handler(state, handler.clone());
102+
}
103+
77104
self.menu.as_mut().map(|menu| {
78105
*menu += command;
79106
*menu += "\n"
@@ -104,7 +131,20 @@ impl Commands {
104131
}
105132
}
106133

107-
#[inline]
134+
fn key_value_pair(s: &'static str) -> Option<&'static str> {
135+
s.match_indices("={}")
136+
.nth(0)
137+
.map(|pair| {
138+
let name = &s[0..pair.0];
139+
if name.len() > 0 {
140+
Some(name)
141+
} else {
142+
None
143+
}
144+
})
145+
.flatten()
146+
}
147+
108148
fn add_space(state_machine: &mut StateMachine, mut state: usize, i: usize) -> usize {
109149
if i > 0 {
110150
let mut char_set = CharacterSet::from_char(' ');
@@ -116,31 +156,40 @@ fn add_space(state_machine: &mut StateMachine, mut state: usize, i: usize) -> us
116156
state
117157
}
118158

119-
#[inline]
120-
fn add_dynamic_segment(state_machine: &mut StateMachine, mut state: usize) -> usize {
159+
fn add_dynamic_segment(
160+
state_machine: &mut StateMachine,
161+
name: &'static str,
162+
mut state: usize,
163+
) -> usize {
121164
let mut char_set = CharacterSet::any();
122165
char_set.remove(' ');
123166
state = state_machine.add(state, char_set);
124167
state_machine.add_next_state(state, state);
125-
state_machine.start_parse(state);
168+
state_machine.start_parse(state, name);
126169
state_machine.end_parse(state);
127170

128171
state
129172
}
130173

131-
#[inline]
132-
fn add_remaining_segment(state_machine: &mut StateMachine, mut state: usize) -> usize {
174+
fn add_remaining_segment(
175+
state_machine: &mut StateMachine,
176+
name: &'static str,
177+
mut state: usize,
178+
) -> usize {
133179
let char_set = CharacterSet::any();
134180
state = state_machine.add(state, char_set);
135181
state_machine.add_next_state(state, state);
136-
state_machine.start_parse(state);
182+
state_machine.start_parse(state, name);
137183
state_machine.end_parse(state);
138184

139185
state
140186
}
141187

142-
#[inline]
143-
fn add_code_segment_multi_line(state_machine: &mut StateMachine, mut state: usize) -> usize {
188+
fn add_code_segment_multi_line(
189+
state_machine: &mut StateMachine,
190+
name: &'static str,
191+
mut state: usize,
192+
) -> usize {
144193
state = state_machine.add(state, CharacterSet::from_char('`'));
145194
state = state_machine.add(state, CharacterSet::from_char('`'));
146195
state = state_machine.add(state, CharacterSet::from_char('`'));
@@ -160,7 +209,7 @@ fn add_code_segment_multi_line(state_machine: &mut StateMachine, mut state: usiz
160209

161210
state = state_machine.add(state, CharacterSet::any());
162211
state_machine.add_next_state(state, state);
163-
state_machine.start_parse(state);
212+
state_machine.start_parse(state, name);
164213
state_machine.end_parse(state);
165214

166215
state = state_machine.add(state, CharacterSet::from_char('`'));
@@ -170,30 +219,39 @@ fn add_code_segment_multi_line(state_machine: &mut StateMachine, mut state: usiz
170219
state
171220
}
172221

173-
#[inline]
174-
fn add_code_segment_single_line_long(state_machine: &mut StateMachine, mut state: usize) -> usize {
175-
state = state_machine.add(state, CharacterSet::from_char('`'));
176-
state = state_machine.add(state, CharacterSet::from_char('`'));
177-
state = state_machine.add(state, CharacterSet::from_char('`'));
222+
fn add_code_segment_single_line(
223+
state_machine: &mut StateMachine,
224+
name: &'static str,
225+
mut state: usize,
226+
n_backticks: usize,
227+
) -> usize {
228+
(0..n_backticks).for_each(|_| {
229+
state = state_machine.add(state, CharacterSet::from_char('`'));
230+
});
178231
state = state_machine.add(state, CharacterSet::any());
179232
state_machine.add_next_state(state, state);
180-
state_machine.start_parse(state);
233+
state_machine.start_parse(state, name);
181234
state_machine.end_parse(state);
182-
state = state_machine.add(state, CharacterSet::from_char('`'));
183-
state = state_machine.add(state, CharacterSet::from_char('`'));
184-
state = state_machine.add(state, CharacterSet::from_char('`'));
235+
(0..n_backticks).for_each(|_| {
236+
state = state_machine.add(state, CharacterSet::from_char('`'));
237+
});
185238

186239
state
187240
}
188241

189-
#[inline]
190-
fn add_code_segment_single_line_short(state_machine: &mut StateMachine, mut state: usize) -> usize {
191-
state = state_machine.add(state, CharacterSet::from_char('`'));
192-
state = state_machine.add(state, CharacterSet::any());
242+
fn add_key_value(state_machine: &mut StateMachine, name: &'static str, mut state: usize) -> usize {
243+
name.chars().for_each(|c| {
244+
state = state_machine.add(state, CharacterSet::from_char(c));
245+
});
246+
state = state_machine.add(state, CharacterSet::from_char('='));
247+
248+
let mut char_set = CharacterSet::any();
249+
char_set.remove(' ');
250+
char_set.remove('\n');
251+
state = state_machine.add(state, char_set);
193252
state_machine.add_next_state(state, state);
194-
state_machine.start_parse(state);
253+
state_machine.start_parse(state, name);
195254
state_machine.end_parse(state);
196-
state = state_machine.add(state, CharacterSet::from_char('`'));
197255

198256
state
199257
}

0 commit comments

Comments
 (0)