1
1
use crate :: state_machine:: { CharacterSet , StateMachine } ;
2
2
use reqwest:: blocking:: Client as HttpClient ;
3
3
use serenity:: { model:: channel:: Message , prelude:: Context } ;
4
- use std:: collections:: HashMap ;
4
+ use std:: { collections:: HashMap , sync :: Arc } ;
5
5
6
6
const PREFIX : & ' static str = "?" ;
7
7
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 > ;
9
9
10
10
pub struct Args < ' m > {
11
11
pub http : & ' m HttpClient ,
@@ -35,45 +35,71 @@ impl Commands {
35
35
handler : impl Fn ( Args ) -> Result < ( ) > + Send + Sync + ' static ,
36
36
) {
37
37
info ! ( "Adding command {}" , & command) ;
38
- let mut param_names = Vec :: new ( ) ;
39
38
let mut state = 0 ;
40
39
40
+ let mut opt_lambda_state: Option < usize > = None ;
41
+ let mut opt_final_states = vec ! [ ] ;
42
+
41
43
command
42
44
. split ( ' ' )
43
45
. filter ( |segment| segment. len ( ) > 0 )
44
46
. enumerate ( )
45
47
. 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 ( & name, & mut self . state_machine , 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 ( & name, & mut self . state_machine , state) ;
58
+ self . state_machine
59
+ . add_next_state ( state, opt_lambda_state. unwrap ( ) ) ;
60
+ opt_final_states. push ( state) ;
61
+ }
66
62
} else {
63
+ opt_lambda_state = None ;
64
+ opt_final_states. truncate ( 0 ) ;
67
65
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 ( name, & mut self . state_machine , state) ;
70
+ } else if segment. starts_with ( "```" ) && segment. ends_with ( "```" ) {
71
+ let name = & segment[ 3 ..segment. len ( ) - 3 ] ;
72
+ state = add_code_segment_single_line_long ( name, & mut self . state_machine , state) ;
73
+ } else if segment. starts_with ( "`" ) && segment. ends_with ( "`" ) {
74
+ let name = & segment[ 1 ..segment. len ( ) - 1 ] ;
75
+ state =
76
+ add_code_segment_single_line_short ( name, & mut self . state_machine , state) ;
77
+ } else if segment. starts_with ( "{" ) && segment. ends_with ( "}" ) {
78
+ let name = & segment[ 1 ..segment. len ( ) - 1 ] ;
79
+ state = add_dynamic_segment ( name, & mut self . state_machine , state) ;
80
+ } else if segment. ends_with ( "..." ) {
81
+ let name = & segment[ ..segment. len ( ) - 3 ] ;
82
+ state = add_remaining_segment ( name, & mut self . state_machine , state) ;
83
+ } else {
84
+ segment. chars ( ) . for_each ( |ch| {
85
+ state = self . state_machine . add ( state, CharacterSet :: from_char ( ch) )
86
+ } ) ;
87
+ }
71
88
}
72
89
} ) ;
73
90
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) ;
91
+ let handler = Arc :: new ( handler) ;
92
+
93
+ if opt_lambda_state. is_some ( ) {
94
+ opt_final_states. iter ( ) . for_each ( |state| {
95
+ self . state_machine . set_final_state ( * state) ;
96
+ self . state_machine . set_handler ( * state, handler. clone ( ) ) ;
97
+ } ) ;
98
+ } else {
99
+ self . state_machine . set_final_state ( state) ;
100
+ self . state_machine . set_handler ( state, handler. clone ( ) ) ;
101
+ }
102
+
77
103
self . menu . as_mut ( ) . map ( |menu| {
78
104
* menu += command;
79
105
* menu += "\n "
@@ -104,7 +130,20 @@ impl Commands {
104
130
}
105
131
}
106
132
107
- #[ inline]
133
+ fn key_value_pair ( s : & ' static str ) -> Option < & ' static str > {
134
+ s. match_indices ( "={}" )
135
+ . nth ( 0 )
136
+ . map ( |pair| {
137
+ let name = & s[ 0 ..pair. 0 ] ;
138
+ if name. len ( ) > 0 {
139
+ Some ( name)
140
+ } else {
141
+ None
142
+ }
143
+ } )
144
+ . flatten ( )
145
+ }
146
+
108
147
fn add_space ( state_machine : & mut StateMachine , mut state : usize , i : usize ) -> usize {
109
148
if i > 0 {
110
149
let mut char_set = CharacterSet :: from_char ( ' ' ) ;
@@ -116,31 +155,40 @@ fn add_space(state_machine: &mut StateMachine, mut state: usize, i: usize) -> us
116
155
state
117
156
}
118
157
119
- #[ inline]
120
- fn add_dynamic_segment ( state_machine : & mut StateMachine , mut state : usize ) -> usize {
158
+ fn add_dynamic_segment (
159
+ name : & ' static str ,
160
+ state_machine : & mut StateMachine ,
161
+ mut state : usize ,
162
+ ) -> usize {
121
163
let mut char_set = CharacterSet :: any ( ) ;
122
164
char_set. remove ( ' ' ) ;
123
165
state = state_machine. add ( state, char_set) ;
124
166
state_machine. add_next_state ( state, state) ;
125
- state_machine. start_parse ( state) ;
167
+ state_machine. start_parse ( state, name ) ;
126
168
state_machine. end_parse ( state) ;
127
169
128
170
state
129
171
}
130
172
131
- #[ inline]
132
- fn add_remaining_segment ( state_machine : & mut StateMachine , mut state : usize ) -> usize {
173
+ fn add_remaining_segment (
174
+ name : & ' static str ,
175
+ state_machine : & mut StateMachine ,
176
+ mut state : usize ,
177
+ ) -> usize {
133
178
let char_set = CharacterSet :: any ( ) ;
134
179
state = state_machine. add ( state, char_set) ;
135
180
state_machine. add_next_state ( state, state) ;
136
- state_machine. start_parse ( state) ;
181
+ state_machine. start_parse ( state, name ) ;
137
182
state_machine. end_parse ( state) ;
138
183
139
184
state
140
185
}
141
186
142
- #[ inline]
143
- fn add_code_segment_multi_line ( state_machine : & mut StateMachine , mut state : usize ) -> usize {
187
+ fn add_code_segment_multi_line (
188
+ name : & ' static str ,
189
+ state_machine : & mut StateMachine ,
190
+ mut state : usize ,
191
+ ) -> usize {
144
192
state = state_machine. add ( state, CharacterSet :: from_char ( '`' ) ) ;
145
193
state = state_machine. add ( state, CharacterSet :: from_char ( '`' ) ) ;
146
194
state = state_machine. add ( state, CharacterSet :: from_char ( '`' ) ) ;
@@ -160,7 +208,7 @@ fn add_code_segment_multi_line(state_machine: &mut StateMachine, mut state: usiz
160
208
161
209
state = state_machine. add ( state, CharacterSet :: any ( ) ) ;
162
210
state_machine. add_next_state ( state, state) ;
163
- state_machine. start_parse ( state) ;
211
+ state_machine. start_parse ( state, name ) ;
164
212
state_machine. end_parse ( state) ;
165
213
166
214
state = state_machine. add ( state, CharacterSet :: from_char ( '`' ) ) ;
@@ -170,14 +218,17 @@ fn add_code_segment_multi_line(state_machine: &mut StateMachine, mut state: usiz
170
218
state
171
219
}
172
220
173
- #[ inline]
174
- fn add_code_segment_single_line_long ( state_machine : & mut StateMachine , mut state : usize ) -> usize {
221
+ fn add_code_segment_single_line_long (
222
+ name : & ' static str ,
223
+ state_machine : & mut StateMachine ,
224
+ mut state : usize ,
225
+ ) -> usize {
175
226
state = state_machine. add ( state, CharacterSet :: from_char ( '`' ) ) ;
176
227
state = state_machine. add ( state, CharacterSet :: from_char ( '`' ) ) ;
177
228
state = state_machine. add ( state, CharacterSet :: from_char ( '`' ) ) ;
178
229
state = state_machine. add ( state, CharacterSet :: any ( ) ) ;
179
230
state_machine. add_next_state ( state, state) ;
180
- state_machine. start_parse ( state) ;
231
+ state_machine. start_parse ( state, name ) ;
181
232
state_machine. end_parse ( state) ;
182
233
state = state_machine. add ( state, CharacterSet :: from_char ( '`' ) ) ;
183
234
state = state_machine. add ( state, CharacterSet :: from_char ( '`' ) ) ;
@@ -186,14 +237,34 @@ fn add_code_segment_single_line_long(state_machine: &mut StateMachine, mut state
186
237
state
187
238
}
188
239
189
- #[ inline]
190
- fn add_code_segment_single_line_short ( state_machine : & mut StateMachine , mut state : usize ) -> usize {
240
+ fn add_code_segment_single_line_short (
241
+ name : & ' static str ,
242
+ state_machine : & mut StateMachine ,
243
+ mut state : usize ,
244
+ ) -> usize {
191
245
state = state_machine. add ( state, CharacterSet :: from_char ( '`' ) ) ;
192
246
state = state_machine. add ( state, CharacterSet :: any ( ) ) ;
193
247
state_machine. add_next_state ( state, state) ;
194
- state_machine. start_parse ( state) ;
248
+ state_machine. start_parse ( state, name ) ;
195
249
state_machine. end_parse ( state) ;
196
250
state = state_machine. add ( state, CharacterSet :: from_char ( '`' ) ) ;
197
251
198
252
state
199
253
}
254
+
255
+ fn add_key_value ( name : & ' static str , state_machine : & mut StateMachine , mut state : usize ) -> usize {
256
+ name. chars ( ) . for_each ( |c| {
257
+ state = state_machine. add ( state, CharacterSet :: from_char ( c) ) ;
258
+ } ) ;
259
+ state = state_machine. add ( state, CharacterSet :: from_char ( '=' ) ) ;
260
+
261
+ let mut char_set = CharacterSet :: any ( ) ;
262
+ char_set. remove ( ' ' ) ;
263
+ char_set. remove ( '\n' ) ;
264
+ state = state_machine. add ( state, char_set) ;
265
+ state_machine. add_next_state ( state, state) ;
266
+ state_machine. start_parse ( state, name) ;
267
+ state_machine. end_parse ( state) ;
268
+
269
+ state
270
+ }
0 commit comments