weechat_relay_rs/
message_parser.rs

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), // FIXME
149    }
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
288// to ensure the type and parser match
289macro_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
379/*
380=== Hashtable parsing ===
381
382Hashtables end up being one of the harder things to parse, because they come as m copies of (a
383priori unknown) two types, interleaved with each other. We lean on generics where we can, but
384ultimately, we have to pass something back to a consumer who doesn't know those types, which means
385an enum that somehow conveys |{ObjectType}|**2 possible variants. The consumer representation of
386this is solved by being a struct with two members, each of which is a WArray (a vec of pairs may
387seem more natural, but would require generics in the type, which again, we can't use; or enums,
388which lose the type consistency). Here though, we still need to somehow call the correct generic
389function, and force the result into this format. This means |{ObjectType}|**2 calls we need to match
390against, which is... unwieldy. To make the best of it, we rely on macros that generate nested match
391statements. For details, see the code itself.
392*/
393
394fn 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
645// to ensure the type and the parser match
646macro_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', // array type
769            0x00, 0x00, 0x00, 0x02, // array length
770            0x00, 0x00, 0x00, 0x03, b'a', b'b', b'c', // element 1
771            0x00, 0x00, 0x00, 0x02, b'd', b'e', // element 2
772        ];
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', // key type
801            b's', b't', b'r', // val type
802            0x00, 0x00, 0x00, 0x02, // number of key-val pairs
803            0x00, 0x00, 0x00, 0x04, b'k', b'e', b'y', b'1', // key 1
804            0x00, 0x00, 0x00, 0x03, b'a', b'b', b'c', // val 1
805            0x00, 0x00, 0x00, 0x04, b'k', b'e', b'y', b'2', // key 2
806            0x00, 0x00, 0x00, 0x03, b'd', b'e', b'f', // val 2
807        ];
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, // h-path length
829            b'b', b'u', b'f', b'f', b'e', b'r', // h-path
830            0x00, 0x00, 0x00, 0x18, // full keys length
831            b'n', b'u', b'm', b'b', b'e', b'r', b':', // key1 name
832            b'i', b'n', b't', b',', // key1 type
833            b'f', b'u', b'l', b'l', b'_', b'n', b'a', b'm', b'e', b':', // key2 name
834            b's', b't', b'r', // key2 type
835            0x00, 0x00, 0x00, 0x02, // count
836            0x05, b'1', b'2', b'3', b'4', b'5', // p-path 1
837            0x00, 0x00, 0x00, 0x01, // buffer 1 val 1
838            0x00, 0x00, 0x00, 0x0C, // buffer 1 val 2 length
839            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', // p-path 2
841            0x00, 0x00, 0x00, 0x02, // buffer 2 val 1
842            0x00, 0x00, 0x00, 0x11, // buffer 2 val 2 length
843            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', // buffer 2 val 2
845        ];
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        // FIXME: there are two more complicated hdatas in the proto docs to test
873
874        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', // name
893            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', //value
895        ];
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', // name
911            0x00, 0x00, 0x00, 0x02, // count
912            0x00, 0x00, 0x00, 0x01, // item 1 count
913            0x00, 0x00, 0x00, 0x07, b'p', b'o', b'i', b'n', b't', b'e',
914            b'r', // item 1 val 1 name
915            b'p', b't', b'r', // item 1 val 1 type
916            0x05, b'1', b'2', b'3', b'4', b'5', // item 1 val 1
917            0x00, 0x00, 0x00, 0x01, // item 2 count
918            0x00, 0x00, 0x00, 0x07, b'p', b'o', b'i', b'n', b't', b'e',
919            b'r', // item 2 val 1 name
920            b'p', b't', b'r', // item 2 val 1 type
921            0x05, b'6', b'7', b'8', b'9', b'a', // item 2 val 1
922        ];
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, // compression
972            0x00, 0x00, 0x00, 0x00, // id length
973            b'c', b'h', b'r', // type 1
974            0xFF, // object 1
975            b'i', b'n', b't', // type 2
976            0x01, 0x03, 0x01, 0x02, // object 2
977        ];
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}