@@ -2,14 +2,31 @@ use std::vec;
2
2
3
3
use thiserror:: Error ;
4
4
5
- use crate :: message:: { frame:: Frame , MessageFrames , MessageType } ;
5
+ use crate :: message:: { frame:: Frame , Message , MessageError , MessageFrames , MessageType } ;
6
6
7
7
#[ derive( Error , Debug ) ]
8
8
pub ( super ) enum ParseError {
9
9
#[ error( "end of stream" ) ]
10
10
EndOfStream ,
11
11
#[ error( "unexpecte frame: {frame:?}" ) ]
12
12
UnexpectedFrame { frame : Frame } ,
13
+ #[ error( "invalid message type: {0}" ) ]
14
+ InvalidMessageType ( #[ from] MessageError ) ,
15
+ #[ error( "expect frame: {0}" ) ]
16
+ Expect ( & ' static str ) ,
17
+ #[ error( "incomplete" ) ]
18
+ Incomplete ,
19
+ }
20
+
21
+ impl ParseError {
22
+ #[ expect( clippy:: needless_pass_by_value) ]
23
+ fn expect ( err : nom:: Err < nom:: error:: Error < & [ u8 ] > > , frame : & ' static str ) -> Self {
24
+ if err. is_incomplete ( ) {
25
+ ParseError :: Incomplete
26
+ } else {
27
+ ParseError :: Expect ( frame)
28
+ }
29
+ }
13
30
}
14
31
15
32
pub ( super ) struct Parse {
@@ -83,3 +100,140 @@ impl Parse {
83
100
self . frames . next ( ) . ok_or ( ParseError :: EndOfStream )
84
101
}
85
102
}
103
+
104
+ pub ( super ) struct Parser ;
105
+
106
+ #[ expect( dead_code) ]
107
+ impl Parser {
108
+ pub ( super ) fn new ( ) -> Self {
109
+ Self
110
+ }
111
+
112
+ pub ( super ) fn parse ( & self , input : & [ u8 ] ) -> Result < Message , ParseError > {
113
+ let ( input, _start) =
114
+ parse:: message_start ( input) . map_err ( |err| ParseError :: expect ( err, "message_start" ) ) ?;
115
+
116
+ let ( input, _frame_length) =
117
+ parse:: frame_length ( input) . map_err ( |err| ParseError :: expect ( err, "frame_length" ) ) ?;
118
+
119
+ let ( input, message_type) =
120
+ parse:: message_type ( input) . map_err ( |err| ParseError :: expect ( err, "message_type" ) ) ?;
121
+ let message_type = MessageType :: try_from ( message_type) ?;
122
+
123
+ match message_type {
124
+ MessageType :: Ping => todo ! ( ) ,
125
+ MessageType :: Authenticate => parse:: authenticate ( input) . map ( Message :: Authenticate ) ,
126
+ MessageType :: Success => todo ! ( ) ,
127
+ MessageType :: Fail => todo ! ( ) ,
128
+ MessageType :: Set => todo ! ( ) ,
129
+ MessageType :: Get => todo ! ( ) ,
130
+ MessageType :: Delete => todo ! ( ) ,
131
+ }
132
+ }
133
+ }
134
+
135
+ mod parse {
136
+ use nom:: {
137
+ bytes:: streaming:: { tag, take} ,
138
+ combinator:: map,
139
+ number:: streaming:: { be_u64, u8} ,
140
+ sequence:: { preceded, terminated} ,
141
+ IResult , Parser as _,
142
+ } ;
143
+
144
+ use crate :: message:: { frame:: prefix, parse:: ParseError , spec, Authenticate } ;
145
+ pub ( super ) fn message_start ( input : & [ u8 ] ) -> IResult < & [ u8 ] , & [ u8 ] > {
146
+ tag ( [ prefix:: MESSAGE_START ] . as_slice ( ) ) ( input)
147
+ }
148
+
149
+ pub ( super ) fn frame_length ( input : & [ u8 ] ) -> IResult < & [ u8 ] , u64 > {
150
+ preceded ( tag ( [ prefix:: FRAME_LENGTH ] . as_slice ( ) ) , u64) . parse ( input)
151
+ }
152
+
153
+ pub ( super ) fn message_type ( input : & [ u8 ] ) -> IResult < & [ u8 ] , u8 > {
154
+ preceded ( tag ( [ prefix:: MESSAGE_TYPE ] . as_slice ( ) ) , u8) . parse ( input)
155
+ }
156
+
157
+ pub ( super ) fn authenticate ( _input : & [ u8 ] ) -> Result < Authenticate , ParseError > {
158
+ todo ! ( )
159
+ }
160
+
161
+ fn delimiter ( input : & [ u8 ] ) -> IResult < & [ u8 ] , ( ) > {
162
+ map ( tag ( spec:: DELIMITER ) , |_| ( ) ) . parse ( input)
163
+ }
164
+
165
+ fn u64 ( input : & [ u8 ] ) -> IResult < & [ u8 ] , u64 > {
166
+ be_u64 ( input)
167
+ }
168
+
169
+ #[ allow( dead_code) ]
170
+ fn string ( input : & [ u8 ] ) -> IResult < & [ u8 ] , & [ u8 ] > {
171
+ let ( input, len) = preceded ( tag ( [ prefix:: STRING ] . as_slice ( ) ) , u64) . parse ( input) ?;
172
+ terminated ( take ( len) , delimiter) . parse ( input)
173
+ }
174
+
175
+ #[ cfg( test) ]
176
+ mod tests {
177
+ use crate :: message:: { frame:: Frame , MessageType } ;
178
+
179
+ use super :: * ;
180
+
181
+ #[ tokio:: test]
182
+ async fn parse_message_start ( ) {
183
+ let mut buf = Vec :: new ( ) ;
184
+ let f = Frame :: MessageStart ;
185
+ f. write ( & mut buf) . await . unwrap ( ) ;
186
+
187
+ let ( remain, message) = message_start ( buf. as_slice ( ) ) . unwrap ( ) ;
188
+ assert ! ( remain. is_empty( ) ) ;
189
+ assert_eq ! ( message, [ prefix:: MESSAGE_START ] . as_slice( ) ) ;
190
+
191
+ let err = message_start ( b"" ) . unwrap_err ( ) ;
192
+ assert ! ( err. is_incomplete( ) ) ;
193
+ }
194
+
195
+ #[ tokio:: test]
196
+ async fn parse_frame_length ( ) {
197
+ let mut buf = Vec :: new ( ) ;
198
+ let f = Frame :: Length ( 100 ) ;
199
+ f. write ( & mut buf) . await . unwrap ( ) ;
200
+
201
+ let ( remain, length) = frame_length ( buf. as_slice ( ) ) . unwrap ( ) ;
202
+ assert_eq ! ( length, 100 ) ;
203
+ assert ! ( remain. is_empty( ) ) ;
204
+
205
+ let err = frame_length ( b"" ) . unwrap_err ( ) ;
206
+ assert ! ( err. is_incomplete( ) ) ;
207
+ }
208
+
209
+ #[ tokio:: test]
210
+ async fn parse_message_type ( ) {
211
+ let mut buf = Vec :: new ( ) ;
212
+ let auth = MessageType :: Authenticate ;
213
+ let f = Frame :: MessageType ( auth) ; // Replace `SomeType` with an actual variant of `MessageType`
214
+ f. write ( & mut buf) . await . unwrap ( ) ;
215
+
216
+ let ( remain, mt) = message_type ( buf. as_slice ( ) ) . unwrap ( ) ;
217
+ assert_eq ! ( mt, auth. into( ) ) ; // Ensure `SomeType` matches the variant used above
218
+ assert ! ( remain. is_empty( ) ) ;
219
+
220
+ let err = message_type ( b"" ) . unwrap_err ( ) ;
221
+ assert ! ( err. is_incomplete( ) ) ;
222
+ }
223
+
224
+ #[ tokio:: test]
225
+ async fn parse_string_frame ( ) {
226
+ for string_data in [ "Hello" , "" , "\r \n " ] {
227
+ let mut buf = Vec :: new ( ) ;
228
+ let f = Frame :: String ( string_data. to_owned ( ) ) ;
229
+ f. write ( & mut buf) . await . unwrap ( ) ;
230
+
231
+ let ( remain, parsed_string) = string ( buf. as_slice ( ) ) . unwrap ( ) ;
232
+ assert_eq ! ( parsed_string, string_data. as_bytes( ) ) ;
233
+ assert ! ( remain. is_empty( ) ) ;
234
+ }
235
+ let err = string ( b"" ) . unwrap_err ( ) ;
236
+ assert ! ( err. is_incomplete( ) ) ;
237
+ }
238
+ }
239
+ }
0 commit comments