1pub use crate::basic_types::{Compression, PasswordHashAlgo, Pointer};
2pub use crate::messages::{
3 Event, GenericHdata, HdataValues, Identifier, InfolistItem, InfolistVariable, Message,
4 MessageType, Object, ObjectType, WArray, WBuffer, WHashtable, WInfo, WInfolist, WString,
5};
6
7use nom::bytes::complete::{take, take_till};
8use nom::combinator::{fail, rest};
9use nom::error::{context, ContextError, ParseError};
10use nom::number::complete::{be_i32, be_i8, be_u32, be_u8};
11use nom::sequence::separated_pair;
12use nom::{IResult, Input, ParseTo, Parser};
13
14use std::io::Read;
15use std::net::TcpStream;
16
17macro_rules! parser_for {
18 (Chr) => {
19 be_i8
20 };
21 (Int) => {
22 be_i32
23 };
24 (Lon) => {
25 parse_long
26 };
27 (Str) => {
28 parse_string
29 };
30 (Buf) => {
31 parse_wbuffer
32 };
33 (Ptr) => {
34 parse_pointer
35 };
36 (Tim) => {
37 parse_time
38 };
39 (Htb) => {
40 parse_hashtable
41 };
42 (Hda) => {
43 parse_hdata
44 };
45 (Inf) => {
46 parse_info
47 };
48 (Inl) => {
49 parse_infolist
50 };
51 (Arr) => {
52 parse_array
53 };
54}
55
56#[derive(Debug)]
57pub enum ParseMessageError<E> {
58 Network(String, std::io::Error),
59 Parser(nom::Err<E>),
60}
61
62impl<E: std::fmt::Debug> std::fmt::Display for ParseMessageError<E> {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 match self {
65 Self::Network(m, e) => writeln!(f, "{}: {}", m, e),
66 Self::Parser(e) => writeln!(f, "failed to parse message: {}", e),
67 }
68 }
69}
70
71impl<E: std::fmt::Debug> std::error::Error for ParseMessageError<E> {}
72
73pub fn get_message<E: ParseError<Vec<u8>> + ContextError<Vec<u8>>>(
74 stream: &mut TcpStream,
75) -> Result<Message, ParseMessageError<nom::error::Error<Vec<u8>>>> {
76 let mut message_size = vec![0u8; 4];
77 stream
78 .read_exact(&mut message_size)
79 .map_err(|e| ParseMessageError::Network("failed to read message size".to_string(), e))?;
80 let size_as_slice: &[u8] = &message_size;
81 let res =
82 be_u32::<_, _>(size_as_slice).map_err(|e: nom::Err<nom::error::Error<&[u8]>>| e.to_owned());
83 let (i, message_size) = match res {
84 Ok(m) => m,
85 Err(e) => {
86 return Err(ParseMessageError::Parser(e));
87 }
88 };
89 debug_assert!(i.is_empty());
90
91 let mut message = vec![0u8; message_size as usize - 4];
92 stream
93 .read_exact(&mut message)
94 .map_err(|e| ParseMessageError::Network("failed to read message body".to_string(), e))?;
95 let message_as_slice: &[u8] = &message;
96 let res = parse_message::<_, _>(message_as_slice)
97 .map_err(|e: nom::Err<nom::error::Error<&[u8]>>| e.to_owned());
98 let (i, message) = match res {
99 Ok(m) => m,
100 Err(e) => {
101 return Err(ParseMessageError::Parser(e));
102 }
103 };
104 debug_assert!(i.is_empty());
105 Ok(message)
106}
107
108pub fn parse_message<I, E>(i: I) -> IResult<I, Message, E>
109where
110 E: ParseError<I> + ContextError<I>,
111 I: Clone + PartialEq + Input<Item = u8> + nom::AsBytes + std::fmt::Debug,
112 <I as Input>::Item: PartialEq<u8>,
113{
114 context("message", |i: I| {
115 let (i, compression) = parse_compression(i)?;
116 assert_eq!(
117 compression,
118 Compression::Off,
119 "Only uncompressed data is supported"
120 );
121
122 let (i, id) = parse_identifier(i)?;
123
124 let mut i = i;
125 let mut objects = vec![];
126 while i.input_len() > 0 {
127 let message_type;
128 (i, message_type) = parse_type(i)?;
129 let object;
130 (i, object) = object_parser(&message_type)(i)?;
131 objects.push(object);
132 }
133
134 let message = Message::new(id, objects);
135 Ok((i, message))
136 })
137 .parse(i)
138}
139
140fn parse_compression<I, E>(i: I) -> IResult<I, Compression, E>
141where
142 E: ParseError<I> + ContextError<I>,
143 I: Clone + Input<Item = u8>,
144{
145 let (i, flag) = context("compression byte", be_u8).parse(i)?;
146 match flag {
147 0 => Ok((i, Compression::Off)),
148 _ => context("compression unsupported", fail()).parse(i), }
150}
151
152fn parse_length<I, E>(i: I) -> IResult<I, Option<usize>, E>
153where
154 E: ParseError<I> + ContextError<I>,
155 I: Clone + Input<Item = u8>,
156{
157 context("length", |i| {
158 let (i, length) = be_i32(i)?;
159 match length {
160 0.. => Ok((i, Some(length as usize))),
161 -1 => Ok((i, None)),
162 _ => fail().parse(i),
163 }
164 })
165 .parse(i)
166}
167
168fn parse_buffer<I, E>(i: I) -> IResult<I, Option<I>, E>
169where
170 E: ParseError<I> + ContextError<I>,
171 I: Clone + Input<Item = u8>,
172{
173 context("buffer", |i| {
174 let (i, length) = parse_length(i)?;
175 if let Some(length) = length {
176 let (i, ret) = take(length)(i)?;
177 Ok((i, Some(ret)))
178 } else {
179 Ok((i, None))
180 }
181 })
182 .parse(i)
183}
184
185fn parse_wbuffer<I, E>(i: I) -> IResult<I, WBuffer, E>
186where
187 E: ParseError<I> + ContextError<I>,
188 I: Clone + Input<Item = u8> + nom::AsBytes,
189{
190 context("wbuffer", |i: I| {
191 let (i, buf) = parse_buffer(i)?;
192 Ok((i, buf.map(|b| b.as_bytes().to_vec())))
193 })
194 .parse(i)
195}
196
197fn parse_string<I, E>(i: I) -> IResult<I, WString, E>
198where
199 E: ParseError<I> + ContextError<I>,
200 I: Clone + Input<Item = u8> + nom::AsBytes,
201{
202 context("string", |i: I| {
203 let (i, buf) = parse_wbuffer(i)?;
204 Ok((i, WString::new(buf)))
205 })
206 .parse(i)
207}
208
209fn parse_identifier<I, E>(i: I) -> IResult<I, Identifier, E>
210where
211 E: ParseError<I> + ContextError<I>,
212 I: Clone + Input<Item = u8> + nom::AsBytes,
213{
214 context("identifier", |i: I| {
215 let (i, id) = parse_buffer(i)?;
216
217 let Some(id) = id else {
218 return Ok((i, Identifier::Client(vec![])));
219 };
220 let id = id.as_bytes();
221 let id = if !id.is_empty() && id[0] == b'_' {
222 match id {
223 b"_buffer_opened" => Identifier::Event(Event::BufferOpened),
224 b"_buffer_type_changed" => Identifier::Event(Event::BufferTypeChanged),
225 b"_buffer_moved" => Identifier::Event(Event::BufferMoved),
226 b"_buffer_merged" => Identifier::Event(Event::BufferMerged),
227 b"_buffer_unmerged" => Identifier::Event(Event::BufferUnmerged),
228 b"_buffer_hidden" => Identifier::Event(Event::BufferHidden),
229 b"_buffer_unhidden" => Identifier::Event(Event::BufferUnhidden),
230 b"_buffer_renamed" => Identifier::Event(Event::BufferRenamed),
231 b"_buffer_title_changed" => Identifier::Event(Event::BufferTitleChanged),
232 b"_buffer_localvar_added" => Identifier::Event(Event::BufferLocalvarAdded),
233 b"_buffer_localvar_changed" => Identifier::Event(Event::BufferLocalvarChanged),
234 b"_buffer_localvar_removed" => Identifier::Event(Event::BufferLocalvarRemoved),
235 b"_buffer_closing" => Identifier::Event(Event::BufferClosing),
236 b"_buffer_cleared" => Identifier::Event(Event::BufferCleared),
237 b"_buffer_line_added" => Identifier::Event(Event::BufferLineAdded),
238 b"_nicklist" => Identifier::Event(Event::Nicklist),
239 b"_nicklist_diff" => Identifier::Event(Event::NicklistDiff),
240 b"_pong" => Identifier::Event(Event::Pong),
241 b"_upgrade" => Identifier::Event(Event::Upgrade),
242 b"_upgrade_ended" => Identifier::Event(Event::UpgradeEnded),
243 _ => {
244 eprintln!(
245 "weechat-relay-rs: Unrecognized reserved identifier\
246 (handling as client identifier): {}",
247 String::from_utf8_lossy(id)
248 );
249 Identifier::Client(id.to_vec())
250 }
251 }
252 } else {
253 Identifier::Client(id.to_vec())
254 };
255 Ok((i, id))
256 })
257 .parse(i)
258}
259
260fn parse_type<I, E>(i: I) -> IResult<I, ObjectType, E>
261where
262 E: ParseError<I> + ContextError<I>,
263 I: Clone + Input + nom::AsBytes,
264{
265 context("identifier", |i: I| {
266 let (i, type_bytes) = take(3usize)(i)?;
267 let type_bytes = type_bytes.as_bytes();
268 let message_type = match type_bytes {
269 b"chr" => ObjectType::Chr,
270 b"int" => ObjectType::Int,
271 b"lon" => ObjectType::Lon,
272 b"str" => ObjectType::Str,
273 b"buf" => ObjectType::Buf,
274 b"ptr" => ObjectType::Ptr,
275 b"tim" => ObjectType::Tim,
276 b"htb" => ObjectType::Htb,
277 b"hda" => ObjectType::Hda,
278 b"inf" => ObjectType::Inf,
279 b"inl" => ObjectType::Inl,
280 b"arr" => ObjectType::Arr,
281 _ => return fail().parse(i),
282 };
283 Ok((i, message_type))
284 })
285 .parse(i)
286}
287
288macro_rules! object_parsers {
290 ( $type:expr, $($possible_type:ident),* ) => {
291 match $type {
292 $(
293 ObjectType::$possible_type => |i: I| -> IResult<I, Object, E> {
294 let (i, ret) = parser_for!($possible_type)(i)?;
295 Ok((i, ret.to_object()))
296 },
297 )*
298 }
299 };
300}
301
302fn object_parser<I, E>(object_type: &ObjectType) -> impl Fn(I) -> IResult<I, Object, E>
303where
304 E: ParseError<I> + ContextError<I>,
305 I: Clone + PartialEq + Input<Item = u8> + nom::AsBytes,
306 <I as Input>::Item: PartialEq<u8>,
307{
308 object_parsers!(
309 object_type,
310 Chr,
311 Int,
312 Lon,
313 Str,
314 Buf,
315 Ptr,
316 Tim,
317 Htb,
318 Hda,
319 Inf,
320 Inl,
321 Arr
322 )
323}
324
325fn parse_long<I, E>(i: I) -> IResult<I, i64, E>
326where
327 E: ParseError<I> + ContextError<I>,
328 I: Clone + Input<Item = u8> + nom::AsBytes,
329{
330 context("long", |i: I| {
331 let (i, len) = be_u8(i)?;
332 let (i, buf) = take(len)(i)?;
333 let int: Option<i64> = buf.as_bytes().parse_to();
334 if let Some(int) = int {
335 Ok((i, int))
336 } else {
337 fail().parse(i)
338 }
339 })
340 .parse(i)
341}
342
343fn parse_pointer<I, E>(i: I) -> IResult<I, Pointer, E>
344where
345 E: ParseError<I> + ContextError<I>,
346 I: Clone + Input<Item = u8> + nom::AsBytes,
347{
348 context("pointer", |i: I| {
349 let (i, len) = be_u8(i)?;
350 let (i, buf) = take(len)(i)?;
351 let pointer = Pointer::new(buf.as_bytes().to_vec());
352 if let Ok(pointer) = pointer {
353 Ok((i, pointer))
354 } else {
355 fail().parse(i)
356 }
357 })
358 .parse(i)
359}
360
361fn parse_time<I, E>(i: I) -> IResult<I, u64, E>
362where
363 E: ParseError<I> + ContextError<I>,
364 I: Clone + Input<Item = u8> + nom::AsBytes,
365{
366 context("time", |i: I| {
367 let (i, len) = be_u8(i)?;
368 let (i, buf) = take(len)(i)?;
369 let int: Option<u64> = buf.as_bytes().parse_to();
370 if let Some(tim) = int {
371 Ok((i, tim))
372 } else {
373 fail().parse(i)
374 }
375 })
376 .parse(i)
377}
378
379fn apply_hashtable_parsers<I, E, M, N>(
395 i: I,
396 key_parser: impl Fn(I) -> IResult<I, M, E>,
397 val_parser: impl Fn(I) -> IResult<I, N, E>,
398) -> IResult<I, Vec<(M, N)>, E>
399where
400 E: ParseError<I>,
401 I: Clone + PartialEq + Input<Item = u8>,
402{
403 let (i, count) = be_u32(i)?;
404 let count = count as usize;
405 nom::multi::count(
406 |i| {
407 let (i, key) = key_parser(i)?;
408 let (i, val) = val_parser(i)?;
409 Ok((i, (key, val)))
410 },
411 count,
412 )
413 .parse(i)
414}
415
416fn pairs_to_hashtable<M, N>(pairs: Vec<(M, N)>) -> WHashtable
417where
418 M: MessageType + Clone,
419 N: MessageType + Clone,
420{
421 let (left, right): (Vec<M>, Vec<N>) = pairs.into_iter().unzip();
422 WHashtable {
423 keys: MessageType::to_warray(left),
424 vals: MessageType::to_warray(right),
425 }
426}
427
428fn apply_and_gen_hashtable<J, M, N, E>(
429 i: J,
430 key_parser: impl Fn(J) -> IResult<J, M, E>,
431 val_parser: impl Fn(J) -> IResult<J, N, E>,
432) -> IResult<J, WHashtable, E>
433where
434 E: ParseError<J> + ContextError<J>,
435 J: Clone + PartialEq + Input<Item = u8>,
436 M: MessageType + Clone,
437 N: MessageType + Clone,
438{
439 let (i, pairs) = apply_hashtable_parsers(i, key_parser, val_parser)?;
440 Ok((i, pairs_to_hashtable(pairs)))
441}
442
443macro_rules! parse_hashtable_match_val {
444 ( $i:expr, $type_keys:ident, $type_vals:expr, $($possible_type:ident),* ) => {
445 match $type_vals {
446 $(
447 ObjectType::$possible_type => apply_and_gen_hashtable(
448 $i, parser_for!($type_keys), parser_for!($possible_type)
449 ),
450 )*
451 }
452 };
453}
454
455macro_rules! parse_hashtable_match_key {
456 ( $i:expr, $type_keys:expr, $type_vals:expr, $($possible_type:ident),* ) => {
457 match $type_keys {
458 $(
459 ObjectType::$possible_type => parse_hashtable_match_val!(
460 $i, $possible_type, $type_vals,
461 Chr, Int, Lon, Str, Buf, Ptr, Tim, Htb, Hda, Inf, Inl, Arr
462 ),
463 )*
464 }
465 };
466}
467
468fn parse_hashtable<I, E>(i: I) -> IResult<I, WHashtable, E>
469where
470 E: ParseError<I> + ContextError<I>,
471 I: Clone + PartialEq + Input<Item = u8> + nom::AsBytes,
472 <I as Input>::Item: PartialEq<u8>,
473{
474 context("hashtable", |i: I| {
475 let (i, type_keys) = parse_type(i)?;
476 let (i, type_vals) = parse_type(i)?;
477
478 parse_hashtable_match_key!(
479 i, type_keys, type_vals, Chr, Int, Lon, Str, Buf, Ptr, Tim, Htb, Hda, Inf, Inl, Arr
480 )
481 })
482 .parse(i)
483}
484
485macro_rules! parse_and_pusher {
486 ( $i:expr, $warr:expr, $($possible_type:ident),* ) => {
487 match $warr {
488 $(
489 WArray::$possible_type(v) => {
490 let (i, r) = parser_for!($possible_type).parse($i)?;
491 Ok((i, v.push(r)))
492 },
493 )*
494 }
495 };
496}
497
498fn parse_and_push<I, E>(i: I, a: &mut WArray) -> IResult<I, (), E>
499where
500 E: ParseError<I> + ContextError<I>,
501 I: Clone + PartialEq + Input<Item = u8> + nom::AsBytes,
502 <I as Input>::Item: PartialEq<u8>,
503{
504 parse_and_pusher!(i, a, Chr, Int, Lon, Str, Buf, Ptr, Tim, Htb, Hda, Inf, Inl, Arr)
505}
506
507fn parse_hdata<I, E>(i: I) -> IResult<I, GenericHdata, E>
508where
509 E: ParseError<I> + ContextError<I>,
510 I: Clone + PartialEq + Input<Item = u8> + nom::AsBytes,
511 <I as Input>::Item: PartialEq<u8>,
512{
513 context("hdata", |i: I| {
514 let (i, hpath) = parse_string(i)?;
515 let (i, raw_keys) = parse_buffer(i)?;
516 let (i, count) = be_u32(i)?;
517
518 let path_depth = if let Some(ref hpath) = hpath.bytes() {
519 hpath.iter().filter(|&b| *b == b'/').count() + 1
520 } else {
521 0
522 };
523 let key_pairs = if let Some(raw_keys) = raw_keys {
524 nom::multi::separated_list0(take(1_usize), take_till(|c| c == b','))
525 .parse(raw_keys)?
526 .1
527 } else {
528 vec![]
529 };
530 let count = count as usize;
531
532 let mut key_data = key_pairs
533 .into_iter()
534 .map(|i| separated_pair(take_till(|c| c == b':'), take(1_usize), rest).parse(i))
535 .map(|r| {
536 r.and_then(|(_, (k, t))| {
537 let t = parse_type(t)?.1;
538 Ok((k, t.new_warray(count)))
539 })
540 })
541 .collect::<Result<Vec<_>, _>>()?;
542
543 let mut ppaths = Vec::with_capacity(count);
544 let mut i = i;
545 for _ in 0..count {
546 let ppath;
547 (i, ppath) = nom::multi::count(parse_pointer, path_depth).parse(i)?;
548 ppaths.push(ppath);
549 for k in key_data.iter_mut() {
550 (i, _) = parse_and_push(i, &mut k.1)?;
551 }
552 }
553
554 let set_values: Vec<_> = key_data
555 .into_iter()
556 .map(|(k, v)| HdataValues {
557 key: k.as_bytes().to_vec(),
558 values: v,
559 })
560 .collect();
561
562 Ok((
563 i,
564 GenericHdata {
565 hpath,
566 ppaths,
567 set_values,
568 },
569 ))
570 })
571 .parse(i)
572}
573
574fn parse_info<I, E>(i: I) -> IResult<I, WInfo, E>
575where
576 E: ParseError<I> + ContextError<I>,
577 I: Clone + PartialEq + Input<Item = u8> + nom::AsBytes,
578{
579 context("info", |i: I| {
580 let (i, name) = parse_string(i)?;
581 let (i, value) = parse_string(i)?;
582 Ok((i, WInfo { name, value }))
583 })
584 .parse(i)
585}
586
587fn parse_infolist_variable<I, E>(i: I) -> IResult<I, InfolistVariable, E>
588where
589 E: ParseError<I> + ContextError<I>,
590 I: Clone + PartialEq + Input<Item = u8> + nom::AsBytes,
591 <I as Input>::Item: PartialEq<u8>,
592{
593 context("infolist variable", |i: I| {
594 let (i, name) = parse_string(i)?;
595 let (i, value_type) = parse_type(i)?;
596 let (i, value) = object_parser(&value_type)(i)?;
597 Ok((i, InfolistVariable { name, value }))
598 })
599 .parse(i)
600}
601
602fn parse_infolist_item<I, E>(i: I) -> IResult<I, InfolistItem, E>
603where
604 E: ParseError<I> + ContextError<I>,
605 I: Clone + PartialEq + Input<Item = u8> + nom::AsBytes,
606 <I as Input>::Item: PartialEq<u8>,
607{
608 context("infolist item", |i: I| {
609 let (i, count) = be_u32(i)?;
610 let count = count as usize;
611 let (i, variables) = nom::multi::count(parse_infolist_variable, count).parse(i)?;
612 Ok((i, InfolistItem { variables }))
613 })
614 .parse(i)
615}
616
617fn parse_infolist<I, E>(i: I) -> IResult<I, WInfolist, E>
618where
619 E: ParseError<I> + ContextError<I>,
620 I: Clone + PartialEq + Input<Item = u8> + nom::AsBytes,
621 <I as Input>::Item: PartialEq<u8>,
622{
623 context("infolist", |i: I| {
624 let (i, name) = parse_string(i)?;
625 let (i, count) = be_u32(i)?;
626 let count = count as usize;
627 let (i, items) = nom::multi::count(parse_infolist_item, count).parse(i)?;
628 Ok((i, WInfolist { name, items }))
629 })
630 .parse(i)
631}
632
633fn parse_array_with<I, E, M>(i: I, parser: impl Fn(I) -> IResult<I, M, E>) -> IResult<I, WArray, E>
634where
635 E: ParseError<I>,
636 I: Clone + PartialEq + Input<Item = u8> + nom::AsBytes,
637 M: MessageType + Clone,
638{
639 let (i, count) = be_u32(i)?;
640 let count = count as usize;
641 let (i, res) = nom::multi::count(parser, count).parse(i)?;
642 Ok((i, MessageType::to_warray(res)))
643}
644
645macro_rules! parse_array_for {
647 ( $i:expr, $type:expr, $($possible_type:ident),* ) => {
648 match $type {
649 $(
650 ObjectType::$possible_type => parse_array_with($i, parser_for!($possible_type)),
651 )*
652 }
653 };
654}
655
656fn parse_array<I, E>(i: I) -> IResult<I, WArray, E>
657where
658 E: ParseError<I> + ContextError<I>,
659 I: Clone + PartialEq + Input<Item = u8> + nom::AsBytes,
660 <I as Input>::Item: PartialEq<u8>,
661{
662 context("array", |i: I| {
663 let (i, item_type) = parse_type(i)?;
664 parse_array_for!(i, item_type, Chr, Int, Lon, Str, Buf, Ptr, Tim, Htb, Hda, Inf, Inl, Arr)
665 })
666 .parse(i)
667}
668
669#[cfg(test)]
670mod tests {
671 use super::*;
672
673 #[test]
674 fn chr_parsing() {
675 let bytes = [b'A'];
676 let res: IResult<_, _> = parser_for!(Chr).parse(&bytes[..]);
677 let c = res.unwrap().1;
678 assert_eq!(c, b'A' as i8);
679 }
680
681 #[test]
682 fn int_parsing() {
683 let bytes = [0x00, 0x01, 0xE2, 0x40];
684 let res: IResult<_, _> = parser_for!(Int).parse(&bytes[..]);
685 let i = res.unwrap().1;
686 assert_eq!(i, 123456);
687
688 let bytes = [0xFF, 0xFE, 0x1D, 0xC0];
689 let res: IResult<_, _> = parser_for!(Int)(&bytes[..]);
690 let i = res.unwrap().1;
691 assert_eq!(i, -123456);
692 }
693
694 #[test]
695 fn lon_parsing() {
696 let bytes = [
697 0x0A, b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'0',
698 ];
699 let res: IResult<_, _> = parser_for!(Lon)(&bytes[..]);
700 let i = res.unwrap().1;
701 assert_eq!(i, 1234567890);
702
703 let bytes = [
704 0x0B, b'-', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'0',
705 ];
706 let res: IResult<_, _> = parser_for!(Lon)(&bytes[..]);
707 let i = res.unwrap().1;
708 assert_eq!(i, -1234567890);
709 }
710
711 #[test]
712 fn str_parsing() {
713 let bytes = [0x00, 0x00, 0x00, 0x05, b'h', b'e', b'l', b'l', b'o'];
714 let res: IResult<_, _> = parser_for!(Str)(&bytes[..]);
715 let s = res.unwrap().1;
716 assert_eq!(s, WString::new(Some(b"hello".to_vec())));
717
718 let bytes = [0x00, 0x00, 0x00, 0x00];
719 let res: IResult<_, _> = parser_for!(Str)(&bytes[..]);
720 let s = res.unwrap().1;
721 assert_eq!(s, WString::new(Some(b"".to_vec())));
722
723 let bytes = [0xFF, 0xFF, 0xFF, 0xFF];
724 let res: IResult<_, _> = parser_for!(Str)(&bytes[..]);
725 let s = res.unwrap().1;
726 assert_eq!(s, WString::new(None));
727 }
728
729 #[test]
730 fn buf_parsing() {
731 let bytes = [0x00, 0x00, 0x00, 0x06, b'b', b'u', b'f', b'f', b'e', b'r'];
732 let res: IResult<_, _> = parser_for!(Buf)(&bytes[..]);
733 let b = res.unwrap().1;
734 assert_eq!(b, Some(b"buffer".to_vec()));
735
736 let bytes = [0xFF, 0xFF, 0xFF, 0xFF];
737 let res: IResult<_, _> = parser_for!(Buf)(&bytes[..]);
738 let b = res.unwrap().1;
739 assert_eq!(b, None);
740 }
741
742 #[test]
743 fn ptr_parsing() {
744 let bytes = [0x09, b'1', b'a', b'2', b'b', b'3', b'c', b'4', b'd', b'5'];
745 let res: IResult<_, _> = parser_for!(Ptr)(&bytes[..]);
746 let p = res.unwrap().1;
747 assert_eq!(p, Pointer::new(b"1a2b3c4d5".to_vec()).unwrap());
748
749 let bytes = [0x01, b'0'];
750 let res: IResult<_, _> = parser_for!(Ptr)(&bytes[..]);
751 let p = res.unwrap().1;
752 assert_eq!(p, Pointer::new(b"0".to_vec()).unwrap());
753 }
754
755 #[test]
756 fn tim_parsing() {
757 let bytes = [
758 0x0A, b'1', b'3', b'2', b'1', b'9', b'9', b'3', b'4', b'5', b'6',
759 ];
760 let res: IResult<_, _> = parser_for!(Tim)(&bytes[..]);
761 let t = res.unwrap().1;
762 assert_eq!(t, 1321993456);
763 }
764
765 #[test]
766 fn arr_parsing() {
767 let bytes = [
768 b's', b't', b'r', 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, b'a', b'b', b'c', 0x00, 0x00, 0x00, 0x02, b'd', b'e', ];
773 let res: IResult<_, _> = parser_for!(Arr)(&bytes[..]);
774 let a = res.unwrap().1;
775 assert_eq!(
776 a,
777 WArray::Str(vec![
778 WString::new(Some(b"abc".to_vec())),
779 WString::new(Some(b"de".to_vec()))
780 ])
781 );
782
783 let bytes = [
784 b'i', b'n', b't', 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x01,
785 0xC8, 0x00, 0x00, 0x03, 0x15,
786 ];
787 let res: IResult<_, _> = parser_for!(Arr)(&bytes[..]);
788 let a = res.unwrap().1;
789 assert_eq!(a, WArray::Int(vec![123, 456, 789]));
790
791 let bytes = [b's', b't', b'r', 0x00, 0x00, 0x00, 0x00];
792 let res: IResult<_, _> = parser_for!(Arr)(&bytes[..]);
793 let a = res.unwrap().1;
794 assert_eq!(a, WArray::Str(vec![]));
795 }
796
797 #[test]
798 fn hashtable_parsing() {
799 let bytes = [
800 b's', b't', b'r', b's', b't', b'r', 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, b'k', b'e', b'y', b'1', 0x00, 0x00, 0x00, 0x03, b'a', b'b', b'c', 0x00, 0x00, 0x00, 0x04, b'k', b'e', b'y', b'2', 0x00, 0x00, 0x00, 0x03, b'd', b'e', b'f', ];
808 let res: IResult<_, _> = parser_for!(Htb)(&bytes[..]);
809 let h = res.unwrap().1;
810 assert_eq!(
811 h,
812 WHashtable {
813 keys: WArray::Str(vec![
814 WString::new(Some(b"key1".to_vec())),
815 WString::new(Some(b"key2".to_vec()))
816 ]),
817 vals: WArray::Str(vec![
818 WString::new(Some(b"abc".to_vec())),
819 WString::new(Some(b"def".to_vec()))
820 ])
821 }
822 );
823 }
824
825 #[test]
826 fn hdata_parsing() {
827 let bytes = [
828 0x00, 0x00, 0x00, 0x06, b'b', b'u', b'f', b'f', b'e', b'r', 0x00, 0x00, 0x00, 0x18, b'n', b'u', b'm', b'b', b'e', b'r', b':', b'i', b'n', b't', b',', b'f', b'u', b'l', b'l', b'_', b'n', b'a', b'm', b'e', b':', b's', b't', b'r', 0x00, 0x00, 0x00, 0x02, 0x05, b'1', b'2', b'3', b'4', b'5', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, b'c', b'o', b'r', b'e', b'.', b'w', b'e', b'e', b'c', b'h', b'a', b't', 0x05, b'6',
840 b'7', b'8', b'9', b'a', 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x11, b'i', b'r', b'c', b'.', b's', b'e', b'r', b'v', b'e', b'r', b'.', b'l', b'i', b'b',
844 b'e', b'r', b'a', ];
846 let res: IResult<_, _> = parser_for!(Hda)(&bytes[..]);
847 let h = res.unwrap().1;
848 assert_eq!(
849 h,
850 GenericHdata {
851 hpath: WString::new(Some(b"buffer".to_vec())),
852 ppaths: vec![
853 vec![Pointer::new(b"12345".to_vec()).unwrap()],
854 vec![Pointer::new(b"6789a".to_vec()).unwrap()]
855 ],
856 set_values: vec![
857 HdataValues {
858 key: b"number".to_vec(),
859 values: WArray::Int(vec![1, 2])
860 },
861 HdataValues {
862 key: b"full_name".to_vec(),
863 values: WArray::Str(vec![
864 WString::new(Some(b"core.weechat".to_vec())),
865 WString::new(Some(b"irc.server.libera".to_vec()))
866 ])
867 }
868 ]
869 }
870 );
871
872 let bytes = [
875 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
876 ];
877 let res: IResult<_, _> = parser_for!(Hda)(&bytes[..]);
878 let h = res.unwrap().1;
879 assert_eq!(
880 h,
881 GenericHdata {
882 hpath: WString::new(None),
883 ppaths: vec![],
884 set_values: vec![]
885 }
886 );
887 }
888
889 #[test]
890 fn info_parsing() {
891 let bytes = [
892 0x00, 0x00, 0x00, 0x07, b'v', b'e', b'r', b's', b'i', b'o', b'n', 0x00, 0x00, 0x00, 0x11, b'W', b'e', b'e', b'C', b'h', b'a', b't', b' ', b'0', b'.',
894 b'3', b'.', b'7', b'-', b'd', b'e', b'v', ];
896 let res: IResult<_, _> = parser_for!(Inf)(&bytes[..]);
897 let i = res.unwrap().1;
898 assert_eq!(
899 i,
900 WInfo {
901 name: WString::new(Some(b"version".to_vec())),
902 value: WString::new(Some(b"WeeChat 0.3.7-dev".to_vec()))
903 }
904 )
905 }
906
907 #[test]
908 fn infolist_parsing() {
909 let bytes = [
910 0x00, 0x00, 0x00, 0x06, b'b', b'u', b'f', b'f', b'e', b'r', 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, b'p', b'o', b'i', b'n', b't', b'e',
914 b'r', b'p', b't', b'r', 0x05, b'1', b'2', b'3', b'4', b'5', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, b'p', b'o', b'i', b'n', b't', b'e',
919 b'r', b'p', b't', b'r', 0x05, b'6', b'7', b'8', b'9', b'a', ];
923 let res: IResult<_, _> = parser_for!(Inl)(&bytes[..]);
924 let i = res.unwrap().1;
925 assert_eq!(
926 i,
927 WInfolist {
928 name: WString::new(Some(b"buffer".to_vec())),
929 items: vec![
930 InfolistItem {
931 variables: vec![InfolistVariable {
932 name: WString::new(Some(b"pointer".to_vec())),
933 value: Pointer::new(b"12345".to_vec()).unwrap().to_object(),
934 }]
935 },
936 InfolistItem {
937 variables: vec![InfolistVariable {
938 name: WString::new(Some(b"pointer".to_vec())),
939 value: Pointer::new(b"6789a".to_vec()).unwrap().to_object(),
940 }]
941 },
942 ]
943 }
944 );
945 }
946
947 #[test]
948 fn compression_parsing() {
949 let bytes = [0_u8];
950 let res: IResult<_, _> = parse_compression(&bytes[..]);
951 let c = res.unwrap().1;
952 assert_eq!(c, Compression::Off);
953 }
954
955 #[test]
956 fn identifier_parsing() {
957 let bytes = [0x00, 0x00, 0x00, 0x03, b'f', b'o', b'o'];
958 let res: IResult<_, _> = parse_identifier(&bytes[..]);
959 let i = res.unwrap().1;
960 assert_eq!(i, Identifier::Client(b"foo".to_vec()));
961
962 let bytes = [0x00, 0x00, 0x00, 0x05, b'_', b'p', b'o', b'n', b'g'];
963 let res: IResult<_, _> = parse_identifier(&bytes[..]);
964 let i = res.unwrap().1;
965 assert_eq!(i, Identifier::Event(Event::Pong));
966 }
967
968 #[test]
969 fn message_parsing() {
970 let bytes = [
971 0x00, 0x00, 0x00, 0x00, 0x00, b'c', b'h', b'r', 0xFF, b'i', b'n', b't', 0x01, 0x03, 0x01, 0x02, ];
978 let res: IResult<_, _> = parse_message(&bytes[..]);
979 let m = res.unwrap().1;
980 assert_eq!(
981 m,
982 Message::new(
983 Identifier::Client(b"".to_vec()),
984 vec![Object::Chr(-1), Object::Int(0x01030102)]
985 )
986 );
987 }
988}