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,72 @@ 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 = 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 ( & 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
+ }
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 ( & 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
+ }
71
89
}
72
90
} ) ;
73
91
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
+
77
104
self . menu . as_mut ( ) . map ( |menu| {
78
105
* menu += command;
79
106
* menu += "\n "
@@ -104,7 +131,20 @@ impl Commands {
104
131
}
105
132
}
106
133
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
+
108
148
fn add_space ( state_machine : & mut StateMachine , mut state : usize , i : usize ) -> usize {
109
149
if i > 0 {
110
150
let mut char_set = CharacterSet :: from_char ( ' ' ) ;
@@ -116,31 +156,40 @@ fn add_space(state_machine: &mut StateMachine, mut state: usize, i: usize) -> us
116
156
state
117
157
}
118
158
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 {
121
164
let mut char_set = CharacterSet :: any ( ) ;
122
165
char_set. remove ( ' ' ) ;
123
166
state = state_machine. add ( state, char_set) ;
124
167
state_machine. add_next_state ( state, state) ;
125
- state_machine. start_parse ( state) ;
168
+ state_machine. start_parse ( state, name ) ;
126
169
state_machine. end_parse ( state) ;
127
170
128
171
state
129
172
}
130
173
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 {
133
179
let char_set = CharacterSet :: any ( ) ;
134
180
state = state_machine. add ( state, char_set) ;
135
181
state_machine. add_next_state ( state, state) ;
136
- state_machine. start_parse ( state) ;
182
+ state_machine. start_parse ( state, name ) ;
137
183
state_machine. end_parse ( state) ;
138
184
139
185
state
140
186
}
141
187
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 {
144
193
state = state_machine. add ( state, CharacterSet :: from_char ( '`' ) ) ;
145
194
state = state_machine. add ( state, CharacterSet :: from_char ( '`' ) ) ;
146
195
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
160
209
161
210
state = state_machine. add ( state, CharacterSet :: any ( ) ) ;
162
211
state_machine. add_next_state ( state, state) ;
163
- state_machine. start_parse ( state) ;
212
+ state_machine. start_parse ( state, name ) ;
164
213
state_machine. end_parse ( state) ;
165
214
166
215
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
170
219
state
171
220
}
172
221
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
+ } ) ;
178
231
state = state_machine. add ( state, CharacterSet :: any ( ) ) ;
179
232
state_machine. add_next_state ( state, state) ;
180
- state_machine. start_parse ( state) ;
233
+ state_machine. start_parse ( state, name ) ;
181
234
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
+ } ) ;
185
238
186
239
state
187
240
}
188
241
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) ;
193
252
state_machine. add_next_state ( state, state) ;
194
- state_machine. start_parse ( state) ;
253
+ state_machine. start_parse ( state, name ) ;
195
254
state_machine. end_parse ( state) ;
196
- state = state_machine. add ( state, CharacterSet :: from_char ( '`' ) ) ;
197
255
198
256
state
199
257
}
0 commit comments