async_rustbus/rustbus_core/message_builder/
body.rs

1use super::ByteOrder;
2use crate::rustbus_core;
3use rustbus_core::message_builder::{MarshalContext, UnmarshalContext};
4use rustbus_core::wire::marshal::traits::{Marshal, SignatureBuffer};
5use rustbus_core::wire::unmarshal::traits::Unmarshal;
6use rustbus_core::wire::validate_raw;
7use rustbus_core::wire::UnixFd;
8use std::sync::Arc;
9
10use arrayvec::ArrayVec;
11
12/// The body accepts everything that implements the Marshal trait (e.g. all basic types, strings, slices, Hashmaps,.....)
13/// And you can of course write an Marshal impl for your own datastrcutures
14#[derive(Debug)]
15pub struct MarshalledMessageBody {
16    buf: Arc<Vec<u8>>,
17    sig: SignatureBuffer,
18
19    // out of band data
20    raw_fds: Vec<rustbus_core::wire::UnixFd>,
21
22    byteorder: ByteOrder,
23}
24
25impl Default for MarshalledMessageBody {
26    fn default() -> Self {
27        Self::new()
28    }
29}
30
31#[derive(Debug, PartialEq)]
32enum SigErr {
33    TooLong,
34    NonBaseDictKey,
35    ArraysTooNested,
36    StructsTooNested,
37    UnexpectedClosingParenthesis,
38    UnexpectedClosingBracket,
39    DictEntryNotInArray,
40    UnknownCharacter,
41    UnclosedStruct,
42    UnclosedDictEntry,
43    ArrayWithNoType,
44    TooManyTypesInDictEntry,
45}
46/*impl From<SigErr> for rustbus_core::signature::Error {
47    fn from(err: SigErr) -> Self {
48        use rustbus_core::signature::Error as RErr;
49        match err {
50            SigErr::TooLong => RErr::TooManyTypes,
51            SigErr::NonBaseDictKey => RErr::ShouldBeBaseType,
52            SigErr::ArraysTooNested | SigErr::StructsTooNested => RErr::NestingTooDeep,
53            SigErr::NonBaseDictKey
54
55
56        }
57    }
58}*/
59const MAX_NESTING_DEPTH: u8 = 32;
60
61fn validate_sig_str(sig: &str) -> Result<(), SigErr> {
62    if sig.len() > 255 {
63        return Err(SigErr::TooLong);
64    }
65    enum Nest {
66        Array,
67        DictEntry(u8), // u8 stores number of elements in dict
68        Struct(bool),  // bool stores if struct is non_empty
69    }
70    let mut stack = ArrayVec::<_, 64>::new();
71    let mut a_cnt = 0; //
72    let mut b_cnt = 0;
73    for c in sig.chars() {
74        match c {
75            'v' | 'a' | '{' | '(' if matches!(stack.last(), Some(&Nest::DictEntry(0))) => {
76                return Err(SigErr::NonBaseDictKey);
77            }
78            'a' if a_cnt >= MAX_NESTING_DEPTH => return Err(SigErr::ArraysTooNested),
79            'a' => {
80                stack.push(Nest::Array);
81                a_cnt += 1;
82                continue;
83            }
84            '(' if b_cnt >= MAX_NESTING_DEPTH => return Err(SigErr::StructsTooNested),
85            '(' => {
86                stack.push(Nest::Struct(false));
87                b_cnt += 1;
88                continue;
89            }
90            ')' if !matches!(stack.pop(), Some(Nest::Struct(true))) => {
91                return Err(SigErr::UnexpectedClosingParenthesis)
92            }
93            ')' => b_cnt -= 1,
94            '{' if !matches!(stack.last(), Some(&Nest::Array)) => {
95                return Err(SigErr::DictEntryNotInArray)
96            }
97            '{' => {
98                stack.push(Nest::DictEntry(0));
99                continue;
100            }
101            '}' if !matches!(stack.pop(), Some(Nest::DictEntry(2))) => {
102                return Err(SigErr::UnexpectedClosingBracket)
103            }
104            'v' | '}' | 'y' | 'b' | 'n' | 'q' | 'i' | 'u' | 'x' | 't' | 'd' | 's' | 'o' | 'g'
105            | 'h' => {}
106            _ => return Err(SigErr::UnknownCharacter),
107        }
108        while matches!(stack.last(), Some(&Nest::Array)) {
109            stack.pop();
110            a_cnt -= 1;
111        }
112        match stack.last_mut() {
113            Some(Nest::DictEntry(cnt)) if *cnt >= 2 => return Err(SigErr::TooManyTypesInDictEntry),
114            Some(Nest::DictEntry(cnt)) => *cnt += 1,
115            Some(Nest::Struct(non_empty)) => *non_empty = true,
116            _ => {}
117        }
118    }
119    if stack.is_empty() {
120        debug_assert_eq!(a_cnt, 0);
121        debug_assert_eq!(b_cnt, 0);
122        Ok(())
123    } else {
124        Err(match stack.last().unwrap() {
125            Nest::Struct(_) => SigErr::UnclosedStruct,
126            Nest::DictEntry(_) => SigErr::UnclosedDictEntry,
127            Nest::Array => SigErr::ArrayWithNoType,
128        })
129    }
130}
131
132impl MarshalledMessageBody {
133    /// New messagebody with the default little endian byteorder
134    #[inline]
135    pub fn new() -> Self {
136        Self::with_byteorder(ByteOrder::LittleEndian)
137    }
138
139    /// New messagebody with a chosen byteorder
140    #[inline]
141    pub fn with_byteorder(b: ByteOrder) -> Self {
142        MarshalledMessageBody {
143            buf: Arc::new(Vec::new()),
144            raw_fds: Vec::new(),
145            sig: SignatureBuffer::new(),
146            byteorder: b,
147        }
148    }
149    #[inline]
150    pub fn from_parts(
151        buf: Vec<u8>,
152        raw_fds: Vec<rustbus_core::wire::UnixFd>,
153        sig: SignatureBuffer,
154        byteorder: ByteOrder,
155    ) -> Self {
156        Self {
157            buf: Arc::new(buf),
158            sig,
159            raw_fds,
160            byteorder,
161        }
162    }
163    #[inline]
164    pub fn sig(&self) -> &str {
165        &self.sig
166    }
167    #[inline]
168    pub fn buf(&self) -> &[u8] {
169        &self.buf
170    }
171    #[inline]
172    pub fn buf_arc(&self) -> Arc<Vec<u8>> {
173        self.buf.clone()
174    }
175    #[inline]
176    pub fn fds(&self) -> &[UnixFd] {
177        &self.raw_fds
178    }
179    #[inline]
180    pub fn byteorder(&self) -> ByteOrder {
181        self.byteorder
182    }
183    /// Get a clone of all the `UnixFd`s in the body.
184    ///
185    /// Some of the `UnixFd`s may already have their `RawFd`s taken.
186    #[inline]
187    pub fn get_fds(&self) -> Vec<UnixFd> {
188        self.raw_fds.clone()
189    }
190    /// Clears the buffer and signature but holds on to the memory allocations. You can now start pushing new
191    /// params as if this were a new message. This allows to reuse the OutMessage for the same dbus-message with different
192    /// parameters without allocating the buffer every time.
193    pub fn reset(&mut self) {
194        self.sig.clear();
195        Arc::make_mut(&mut self.buf).clear();
196    }
197
198    /// Reserves space for `additional` bytes in the internal buffer. This is useful to reduce the amount of allocations done while marshalling,
199    /// if you can predict somewhat accuratly how many bytes you will be marshalling.
200    pub fn reserve(&mut self, additional: usize) {
201        Arc::make_mut(&mut self.buf).reserve(additional)
202    }
203    fn create_ctx2(&mut self) -> (MarshalContext, &mut SignatureBuffer) {
204        (
205            MarshalContext {
206                buf: Arc::make_mut(&mut self.buf),
207                fds: &mut self.raw_fds,
208                byteorder: self.byteorder,
209            },
210            &mut self.sig,
211        )
212    }
213    pub fn push_param_helper<F>(&mut self, push_fn: F) -> Result<(), rustbus_core::Error>
214    where
215        F: FnOnce(&mut MarshalContext, &mut SignatureBuffer) -> Result<(), rustbus_core::Error>,
216    {
217        let fd_pre_cnt = self.raw_fds.len();
218        let buf_pre_len = self.buf.len();
219        let sig_pre_len = self.sig.len();
220        let (mut ctx, sig) = self.create_ctx2();
221        match push_fn(&mut ctx, sig) {
222            Err(e) => {
223                self.raw_fds.truncate(fd_pre_cnt);
224                Arc::make_mut(&mut self.buf).truncate(buf_pre_len);
225                self.sig.truncate(sig_pre_len).unwrap();
226                Err(e)
227            }
228            Ok(()) => Ok(()),
229        }
230    }
231    fn push_param_core<P: Marshal>(
232        ctx: &mut MarshalContext,
233        sig: &mut SignatureBuffer,
234        p: P,
235    ) -> Result<(), rustbus_core::Error> {
236        p.marshal(ctx)?;
237        let pre_len = sig.len();
238        P::sig_str(sig);
239        if sig.len() > 255 {
240            let sig_err = rustbus_core::signature::Error::TooManyTypes;
241            let val_err = rustbus_core::ValError::InvalidSignature(sig_err);
242            Err(rustbus_core::Error::Validation(val_err))
243        } else if let Err(err) = validate_sig_str(&sig[pre_len..]) {
244            if !matches!(err, SigErr::ArraysTooNested | SigErr::StructsTooNested) {
245                panic!(
246                    "Invalid segment of signature added '{}'!: {:?}",
247                    &sig[pre_len..],
248                    err
249                );
250            }
251            let sig_err = rustbus_core::signature::Error::NestingTooDeep;
252            let val_err = rustbus_core::ValError::InvalidSignature(sig_err);
253            Err(rustbus_core::Error::Validation(val_err))
254        } else {
255            Ok(())
256        }
257    }
258    /// Append something that is Marshal to the message body
259    pub fn push_param<P: Marshal>(&mut self, p: P) -> Result<(), rustbus_core::Error> {
260        let push_fn = move |ctx: &mut MarshalContext, sig: &mut SignatureBuffer| {
261            Self::push_param_core(ctx, sig, p)
262        };
263        self.push_param_helper(push_fn)
264    }
265    /// Append two things that are Marshal to the message body
266    pub fn push_param2<P1: Marshal, P2: Marshal>(
267        &mut self,
268        p1: P1,
269        p2: P2,
270    ) -> Result<(), rustbus_core::Error> {
271        let push_fn = move |ctx: &mut MarshalContext, sig: &mut SignatureBuffer| {
272            Self::push_param_core(ctx, sig, p1)?;
273            Self::push_param_core(ctx, sig, p2)
274        };
275        self.push_param_helper(push_fn)
276    }
277
278    /// Append three things that are Marshal to the message body
279    pub fn push_param3<P1: Marshal, P2: Marshal, P3: Marshal>(
280        &mut self,
281        p1: P1,
282        p2: P2,
283        p3: P3,
284    ) -> Result<(), rustbus_core::Error> {
285        let push_fn = move |ctx: &mut MarshalContext, sig: &mut SignatureBuffer| {
286            Self::push_param_core(ctx, sig, p1)?;
287            Self::push_param_core(ctx, sig, p2)?;
288            Self::push_param_core(ctx, sig, p3)
289        };
290        self.push_param_helper(push_fn)
291    }
292
293    /// Append four things that are Marshal to the message body
294    pub fn push_param4<P1: Marshal, P2: Marshal, P3: Marshal, P4: Marshal>(
295        &mut self,
296        p1: P1,
297        p2: P2,
298        p3: P3,
299        p4: P4,
300    ) -> Result<(), rustbus_core::Error> {
301        let push_fn = move |ctx: &mut MarshalContext, sig: &mut SignatureBuffer| {
302            Self::push_param_core(ctx, sig, p1)?;
303            Self::push_param_core(ctx, sig, p2)?;
304            Self::push_param_core(ctx, sig, p3)?;
305            Self::push_param_core(ctx, sig, p4)
306        };
307        self.push_param_helper(push_fn)
308    }
309
310    /// Append five things that are Marshal to the message body
311    pub fn push_param5<P1: Marshal, P2: Marshal, P3: Marshal, P4: Marshal, P5: Marshal>(
312        &mut self,
313        p1: P1,
314        p2: P2,
315        p3: P3,
316        p4: P4,
317        p5: P5,
318    ) -> Result<(), rustbus_core::Error> {
319        let push_fn = move |ctx: &mut MarshalContext, sig: &mut SignatureBuffer| {
320            Self::push_param_core(ctx, sig, p1)?;
321            Self::push_param_core(ctx, sig, p2)?;
322            Self::push_param_core(ctx, sig, p3)?;
323            Self::push_param_core(ctx, sig, p4)?;
324            Self::push_param_core(ctx, sig, p5)
325        };
326        self.push_param_helper(push_fn)
327    }
328
329    /// Append any number of things that have the same type that is Marshal to the message body
330    pub fn push_params<P: Marshal>(&mut self, params: &[P]) -> Result<(), rustbus_core::Error> {
331        let push_fn = move |ctx: &mut MarshalContext, sig: &mut SignatureBuffer| {
332            for p in params {
333                Self::push_param_core(ctx, sig, p)?;
334            }
335            Ok(())
336        };
337        self.push_param_helper(push_fn)
338    }
339
340    /// Append something that is Marshal to the body but use a dbus Variant in the signature. This is necessary for some APIs
341    pub fn push_variant<P: Marshal>(&mut self, p: P) -> Result<(), rustbus_core::Error> {
342        let push_fn = move |ctx: &mut MarshalContext, sig: &mut SignatureBuffer| {
343            p.marshal_as_variant(ctx)?;
344            sig.push_static("v");
345            if sig.len() > 255 {
346                let sig_err = rustbus_core::signature::Error::TooManyTypes;
347                let val_err = rustbus_core::ValError::InvalidSignature(sig_err);
348                Err(rustbus_core::Error::Validation(val_err))
349            } else {
350                Ok(())
351            }
352        };
353        self.push_param_helper(push_fn)
354    }
355    /// Validate the all the marshalled elements of the body.
356    pub fn validate(&self) -> Result<(), rustbus_core::wire::unmarshal::Error> {
357        if self.sig.is_empty() && self.buf.is_empty() {
358            return Ok(());
359        }
360        let types = rustbus_core::signature::Type::parse_description(&self.sig)?;
361        let mut used = 0;
362        for typ in types {
363            used += validate_raw::validate_marshalled(self.byteorder, used, &self.buf, &typ)
364                .map_err(|(_, e)| e)?;
365        }
366        if used == self.buf.len() {
367            Ok(())
368        } else {
369            Err(rustbus_core::wire::unmarshal::Error::NotAllBytesUsed)
370        }
371    }
372    /// Create a parser to retrieve parameters from the body.
373    #[inline]
374    pub fn parser(&self) -> MessageBodyParser {
375        MessageBodyParser::new(self)
376    }
377}
378
379/// Iterate over the messages parameters
380///
381/// Because dbus allows for multiple toplevel params without an enclosing struct, this provides a simple Iterator (sadly not std::iterator::Iterator, since the types
382/// of the parameters can be different)
383/// that you can use to get the params one by one, calling `get::<T>` until you have obtained all the parameters.
384/// If you try to get more parameters than the signature has types, it will return None, if you try to get a parameter that doesn not
385/// fit the current one, it will return an Error::WrongSignature, but you can safely try other types, the iterator stays valid.
386#[derive(Debug)]
387pub struct MessageBodyParser<'body> {
388    buf_idx: usize,
389    sig_idx: usize,
390    sigs: Vec<rustbus_core::signature::Type>,
391    body: &'body MarshalledMessageBody,
392}
393
394impl<'ret, 'fds, 'body: 'ret + 'fds> MessageBodyParser<'body> {
395    pub fn new(body: &'body MarshalledMessageBody) -> Self {
396        let sigs = match rustbus_core::signature::Type::parse_description(&body.sig) {
397            Ok(sigs) => sigs,
398            Err(e) => match e {
399                rustbus_core::signature::Error::EmptySignature => Vec::new(),
400                _ => panic!("MarshalledMessageBody has bad signature: {:?}", e),
401            },
402        };
403        Self {
404            buf_idx: 0,
405            sig_idx: 0,
406            sigs,
407            body,
408        }
409    }
410
411    /// Get the next params signature (if any are left)
412    pub fn get_next_sig(&self) -> Option<&rustbus_core::signature::Type> {
413        self.sigs.get(self.sig_idx)
414    }
415
416    /// Get the remaining params signature (if any are left)
417    pub fn get_left_sigs(&self) -> Option<&[rustbus_core::signature::Type]> {
418        self.sigs.get(self.sig_idx..)
419    }
420
421    /// Get the next param, use get::<TYPE> to specify what type you expect. For example `let s = parser.get::<String>()?;`
422    /// This checks if there are params left in the message and if the type you requested fits the signature of the message.
423    pub fn get<T: Unmarshal<'body, 'fds>>(
424        &mut self,
425    ) -> Result<T, rustbus_core::wire::unmarshal::Error> {
426        if self.sig_idx >= self.sigs.len() {
427            return Err(rustbus_core::wire::unmarshal::Error::EndOfMessage);
428        }
429        if self.sigs[self.sig_idx] != T::signature() {
430            return Err(rustbus_core::wire::unmarshal::Error::WrongSignature);
431        }
432
433        let mut ctx = UnmarshalContext {
434            byteorder: self.body.byteorder,
435            buf: &self.body.buf,
436            offset: self.buf_idx,
437            fds: &self.body.raw_fds,
438        };
439        match T::unmarshal(&mut ctx) {
440            Ok((bytes, res)) => {
441                self.buf_idx += bytes;
442                self.sig_idx += 1;
443                Ok(res)
444            }
445            Err(e) => Err(e),
446        }
447    }
448    /// Perform error handling for `get2(), get3()...` if `get_calls` fails.
449    fn get_mult_helper<T, F>(
450        &mut self,
451        count: usize,
452        get_calls: F,
453    ) -> Result<T, rustbus_core::wire::unmarshal::Error>
454    where
455        F: FnOnce(&mut Self) -> Result<T, rustbus_core::wire::unmarshal::Error>,
456    {
457        if self.sig_idx + count > self.sigs.len() {
458            return Err(rustbus_core::wire::unmarshal::Error::EndOfMessage);
459        }
460        let start_sig_idx = self.sig_idx;
461        let start_buf_idx = self.buf_idx;
462        match get_calls(self) {
463            Ok(ret) => Ok(ret),
464            Err(err) => {
465                self.sig_idx = start_sig_idx;
466                self.buf_idx = start_buf_idx;
467                Err(err)
468            }
469        }
470    }
471
472    /// Get the next two params, use get2::<TYPE, TYPE> to specify what type you expect. For example `let s = parser.get2::<String, i32>()?;`
473    /// This checks if there are params left in the message and if the type you requested fits the signature of the message.
474    pub fn get2<T1, T2>(&mut self) -> Result<(T1, T2), rustbus_core::wire::unmarshal::Error>
475    where
476        T1: Unmarshal<'body, 'fds>,
477        T2: Unmarshal<'body, 'fds>,
478    {
479        let get_calls = |parser: &mut Self| {
480            let ret1 = parser.get()?;
481            let ret2 = parser.get()?;
482            Ok((ret1, ret2))
483        };
484        self.get_mult_helper(2, get_calls)
485    }
486
487    /// Get the next three params, use get3::<TYPE, TYPE, TYPE> to specify what type you expect. For example `let s = parser.get3::<String, i32, u64>()?;`
488    /// This checks if there are params left in the message and if the type you requested fits the signature of the message.
489    pub fn get3<T1, T2, T3>(&mut self) -> Result<(T1, T2, T3), rustbus_core::wire::unmarshal::Error>
490    where
491        T1: Unmarshal<'body, 'fds>,
492        T2: Unmarshal<'body, 'fds>,
493        T3: Unmarshal<'body, 'fds>,
494    {
495        let get_calls = |parser: &mut Self| {
496            let ret1 = parser.get()?;
497            let ret2 = parser.get()?;
498            let ret3 = parser.get()?;
499            Ok((ret1, ret2, ret3))
500        };
501        self.get_mult_helper(3, get_calls)
502    }
503
504    /// Get the next four params, use get4::<TYPE, TYPE, TYPE, TYPE> to specify what type you expect. For example `let s = parser.get4::<String, i32, u64, u8>()?;`
505    /// This checks if there are params left in the message and if the type you requested fits the signature of the message.
506    pub fn get4<T1, T2, T3, T4>(
507        &mut self,
508    ) -> Result<(T1, T2, T3, T4), rustbus_core::wire::unmarshal::Error>
509    where
510        T1: Unmarshal<'body, 'fds>,
511        T2: Unmarshal<'body, 'fds>,
512        T3: Unmarshal<'body, 'fds>,
513        T4: Unmarshal<'body, 'fds>,
514    {
515        let get_calls = |parser: &mut Self| {
516            let ret1 = parser.get()?;
517            let ret2 = parser.get()?;
518            let ret3 = parser.get()?;
519            let ret4 = parser.get()?;
520            Ok((ret1, ret2, ret3, ret4))
521        };
522        self.get_mult_helper(4, get_calls)
523    }
524
525    /// Get the next five params, use get5::<TYPE, TYPE, TYPE, TYPE, TYPE> to specify what type you expect. For example `let s = parser.get4::<String, i32, u64, u8, bool>()?;`
526    /// This checks if there are params left in the message and if the type you requested fits the signature of the message.
527    pub fn get5<T1, T2, T3, T4, T5>(
528        &mut self,
529    ) -> Result<(T1, T2, T3, T4, T5), rustbus_core::wire::unmarshal::Error>
530    where
531        T1: Unmarshal<'body, 'fds>,
532        T2: Unmarshal<'body, 'fds>,
533        T3: Unmarshal<'body, 'fds>,
534        T4: Unmarshal<'body, 'fds>,
535        T5: Unmarshal<'body, 'fds>,
536    {
537        let get_calls = |parser: &mut Self| {
538            let ret1 = parser.get()?;
539            let ret2 = parser.get()?;
540            let ret3 = parser.get()?;
541            let ret4 = parser.get()?;
542            let ret5 = parser.get()?;
543            Ok((ret1, ret2, ret3, ret4, ret5))
544        };
545        self.get_mult_helper(5, get_calls)
546    }
547}
548
549#[test]
550fn test_marshal_trait() {
551    let mut body = MarshalledMessageBody::new();
552    let bytes: &[&[_]] = &[&[4u64]];
553    body.push_param(bytes).unwrap();
554
555    assert_eq!(
556        [12, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0],
557        &body.buf[..]
558    );
559    assert_eq!(body.sig.as_str(), "aat");
560
561    let mut body = MarshalledMessageBody::new();
562    let mut map = std::collections::HashMap::new();
563    map.insert("a", 4u32);
564
565    body.push_param(&map).unwrap();
566    assert_eq!(
567        [12, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, b'a', 0, 0, 0, 4, 0, 0, 0,],
568        &body.buf[..]
569    );
570    assert_eq!(body.sig.as_str(), "a{su}");
571
572    let mut body = MarshalledMessageBody::new();
573    body.push_param((11u64, "str", true)).unwrap();
574    assert_eq!(body.sig.as_str(), "(tsb)");
575    assert_eq!(
576        [11, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, b's', b't', b'r', 0, 1, 0, 0, 0,],
577        &body.buf[..]
578    );
579
580    struct MyStruct {
581        x: u64,
582        y: String,
583    }
584
585    use rustbus_core::wire::marshal::traits::Signature;
586    use rustbus_core::wire::marshal::MarshalContext;
587    impl Signature for &MyStruct {
588        fn signature() -> rustbus_core::signature::Type {
589            rustbus_core::signature::Type::Container(rustbus_core::signature::Container::Struct(
590                rustbus_core::signature::StructTypes::new(vec![
591                    u64::signature(),
592                    String::signature(),
593                ])
594                .unwrap(),
595            ))
596        }
597
598        fn alignment() -> usize {
599            8
600        }
601    }
602    impl Marshal for &MyStruct {
603        fn marshal(&self, ctx: &mut MarshalContext) -> Result<(), rustbus_core::Error> {
604            // always align to 8
605            ctx.align_to(8);
606            self.x.marshal(ctx)?;
607            self.y.marshal(ctx)?;
608            Ok(())
609        }
610    }
611
612    let mut body = MarshalledMessageBody::new();
613    body.push_param(&MyStruct {
614        x: 100,
615        y: "A".to_owned(),
616    })
617    .unwrap();
618    assert_eq!(body.sig.as_str(), "(ts)");
619    assert_eq!(
620        [100, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, b'A', 0,],
621        &body.buf[..]
622    );
623
624    let mut body = MarshalledMessageBody::new();
625    let emptymap: std::collections::HashMap<&str, u32> = std::collections::HashMap::new();
626    let mut map = std::collections::HashMap::new();
627    let mut map2 = std::collections::HashMap::new();
628    map.insert("a", 4u32);
629    map2.insert("a", &map);
630
631    body.push_param(&map2).unwrap();
632    body.push_param(&emptymap).unwrap();
633    assert_eq!(body.sig.as_str(), "a{sa{su}}a{su}");
634    assert_eq!(
635        [
636            28, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, b'a', 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
637            0, b'a', 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0
638        ],
639        &body.buf[..]
640    );
641
642    // try to unmarshal stuff
643    let mut body_iter = MessageBodyParser::new(&body);
644
645    // first try some stuff that has the wrong signature
646    type WrongNestedDict =
647        std::collections::HashMap<String, std::collections::HashMap<String, u64>>;
648    assert_eq!(
649        body_iter.get::<WrongNestedDict>().err().unwrap(),
650        rustbus_core::wire::unmarshal::Error::WrongSignature
651    );
652    type WrongStruct = (u64, i32, String);
653    assert_eq!(
654        body_iter.get::<WrongStruct>().err().unwrap(),
655        rustbus_core::wire::unmarshal::Error::WrongSignature
656    );
657
658    // the get the correct type and make sure the content is correct
659    type NestedDict = std::collections::HashMap<String, std::collections::HashMap<String, u32>>;
660    let newmap2: NestedDict = body_iter.get().unwrap();
661    assert_eq!(newmap2.len(), 1);
662    assert_eq!(newmap2.get("a").unwrap().len(), 1);
663    assert_eq!(*newmap2.get("a").unwrap().get("a").unwrap(), 4);
664
665    // again try some stuff that has the wrong signature
666    assert_eq!(
667        body_iter.get::<WrongNestedDict>().err().unwrap(),
668        rustbus_core::wire::unmarshal::Error::WrongSignature
669    );
670    assert_eq!(
671        body_iter.get::<WrongStruct>().err().unwrap(),
672        rustbus_core::wire::unmarshal::Error::WrongSignature
673    );
674
675    // get the empty map next
676    let newemptymap: std::collections::HashMap<&str, u32> = body_iter.get().unwrap();
677    assert_eq!(newemptymap.len(), 0);
678
679    // test get2()
680    let mut body_iter = body.parser();
681    assert_eq!(
682        body_iter.get2::<NestedDict, u16>().unwrap_err(),
683        rustbus_core::wire::unmarshal::Error::WrongSignature
684    );
685    assert_eq!(
686        body_iter
687            .get3::<NestedDict, std::collections::HashMap<&str, u32>, u32>()
688            .unwrap_err(),
689        rustbus_core::wire::unmarshal::Error::EndOfMessage
690    );
691
692    // test to make sure body_iter is left unchanged from last failure and the map is
693    // pulled out identically from above
694    let (newmap2, newemptymap): (NestedDict, std::collections::HashMap<&str, u32>) =
695        body_iter.get2().unwrap();
696    // repeat assertions from above
697    assert_eq!(newmap2.len(), 1);
698    assert_eq!(newmap2.get("a").unwrap().len(), 1);
699    assert_eq!(*newmap2.get("a").unwrap().get("a").unwrap(), 4);
700    assert_eq!(newemptymap.len(), 0);
701    assert_eq!(
702        body_iter.get::<u16>().unwrap_err(),
703        rustbus_core::wire::unmarshal::Error::EndOfMessage
704    );
705
706    // test mixed get() and get_param()
707    let mut body_iter = body.parser();
708
709    // test to make sure body_iter is left unchanged from last failure and the map is
710    // pulled out identically from above
711    let newmap2: NestedDict = body_iter.get().unwrap();
712    // repeat assertions from above
713    assert_eq!(newmap2.len(), 1);
714    assert_eq!(newmap2.get("a").unwrap().len(), 1);
715    assert_eq!(*newmap2.get("a").unwrap().get("a").unwrap(), 4);
716}
717
718#[cfg(test)]
719mod tests {
720    use super::{validate_sig_str, SigErr};
721    use rustbus::params::validate_signature;
722
723    #[test]
724    fn test_validate_sig_str() {
725        for _ in 0..1000000 {
726            validate_sig_str("aaai").unwrap();
727            validate_sig_str("a{ii}").unwrap();
728            validate_sig_str("(ii)").unwrap();
729            validate_sig_str("(i)").unwrap();
730            validate_sig_str("a{i(i)}").unwrap();
731            /*assert_eq!(validate_sig_str("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaai"), Err(SigErr::ArraysTooNested));
732            assert_eq!(validate_sig_str("(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i)))))))))))))))))))))))))))))))))"), Err(SigErr::StructsTooNested));
733            assert_eq!(validate_sig_str(
734                "(((((((((((((((((((((((((((((((((y)))))))))))))))))))))))))))))))))"),
735                Err(SigErr::StructsTooNested)
736            );*/
737            assert_eq!(validate_sig_str("{ii}"), Err(SigErr::DictEntryNotInArray));
738            assert_eq!(
739                validate_sig_str("a{i(i})"),
740                Err(SigErr::UnexpectedClosingBracket)
741            );
742            assert_eq!(
743                validate_sig_str("()"),
744                Err(SigErr::UnexpectedClosingParenthesis)
745            );
746            assert_eq!(
747                validate_sig_str("a{}"),
748                Err(SigErr::UnexpectedClosingBracket)
749            );
750            assert_eq!(
751                validate_sig_str("a{iii}"),
752                Err(SigErr::TooManyTypesInDictEntry)
753            );
754            assert_eq!(validate_sig_str("((i)"), Err(SigErr::UnclosedStruct));
755            assert_eq!(
756                validate_sig_str("(i))"),
757                Err(SigErr::UnexpectedClosingParenthesis)
758            );
759            assert_eq!(validate_sig_str("a{{i}i}"), Err(SigErr::NonBaseDictKey));
760            assert_eq!(
761                validate_sig_str("a{ii}}"),
762                Err(SigErr::UnexpectedClosingBracket)
763            );
764            assert_eq!(validate_sig_str("!!!"), Err(SigErr::UnknownCharacter));
765            assert_eq!(
766                validate_sig_str(std::str::from_utf8(&[b'b'; 256]).unwrap()),
767                Err(SigErr::TooLong)
768            );
769            assert_eq!(validate_sig_str("(i)a"), Err(SigErr::ArrayWithNoType));
770        }
771    }
772    #[test]
773    fn test_rb_validate_signature() {
774        for _ in 0..1000000 {
775            validate_signature("aaai").unwrap();
776            validate_signature("a{ii}").unwrap();
777            validate_signature("(ii)").unwrap();
778            validate_signature("(i)").unwrap();
779            validate_signature("a{i(i)}").unwrap();
780            validate_signature("").unwrap();
781            /*validate_signature("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaai").unwrap_err();
782            validate_signature("(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i(i)))))))))))))))))))))))))))))))))").unwrap_err();
783            validate_signature("(((((((((((((((((((((((((((((((((y)))))))))))))))))))))))))))))))))").unwrap_err();
784            */
785            validate_signature("{ii}").unwrap_err();
786            validate_signature("a{i(i})").unwrap_err();
787            validate_signature("()").unwrap();
788            validate_signature("a{}").unwrap_err();
789            validate_signature("a{iii}").unwrap_err();
790            validate_signature("((i)").unwrap_err();
791            validate_signature("(i))").unwrap_err();
792            validate_signature("a{{i}i}").unwrap_err();
793            validate_signature("a{ii}}").unwrap_err();
794            validate_signature("!!!").unwrap_err();
795            validate_signature(std::str::from_utf8(&[b'b'; 256]).unwrap()).unwrap_err();
796            validate_signature("(i)a").unwrap_err();
797        }
798    }
799}