rustbus/
message_builder.rs

1//! Build new messages that you want to send over a connection
2use crate::params::message;
3use crate::signature::SignatureIter;
4use crate::wire::errors::MarshalError;
5use crate::wire::errors::UnmarshalError;
6use crate::wire::marshal::traits::{Marshal, SignatureBuffer};
7use crate::wire::marshal::MarshalContext;
8use crate::wire::unmarshal::UnmarshalContext;
9use crate::wire::validate_raw;
10use crate::wire::UnixFd;
11use crate::ByteOrder;
12
13/// Types a message might have
14#[derive(Copy, Clone, Debug, PartialEq, Eq)]
15pub enum MessageType {
16    Signal,
17    Error,
18    Call,
19    Reply,
20    Invalid,
21}
22
23/// Flags that can be set in the message header
24#[derive(Copy, Clone, PartialEq, Eq)]
25pub enum HeaderFlags {
26    NoReplyExpected,
27    NoAutoStart,
28    AllowInteractiveAuthorization,
29}
30
31impl HeaderFlags {
32    pub fn into_raw(self) -> u8 {
33        match self {
34            HeaderFlags::NoReplyExpected => 1,
35            HeaderFlags::NoAutoStart => 2,
36            HeaderFlags::AllowInteractiveAuthorization => 4,
37        }
38    }
39
40    pub fn is_set(self, flags: u8) -> bool {
41        flags & self.into_raw() == 1
42    }
43
44    pub fn set(self, flags: &mut u8) {
45        *flags |= self.into_raw()
46    }
47
48    pub fn unset(self, flags: &mut u8) {
49        *flags &= 0xFF - self.into_raw()
50    }
51    pub fn toggle(self, flags: &mut u8) {
52        if self.is_set(*flags) {
53            self.unset(flags)
54        } else {
55            self.set(flags)
56        }
57    }
58}
59
60/// The dynamic part of a dbus message header
61#[derive(Debug, Clone, Default)]
62pub struct DynamicHeader {
63    pub interface: Option<String>,
64    pub member: Option<String>,
65    pub object: Option<String>,
66    pub destination: Option<String>,
67    pub serial: Option<u32>,
68    pub sender: Option<String>,
69    pub signature: Option<String>,
70    pub error_name: Option<String>,
71    pub response_serial: Option<u32>,
72    pub num_fds: Option<u32>,
73}
74
75impl DynamicHeader {
76    /// Make a correctly addressed error response with the correct response serial
77    pub fn make_error_response<S: Into<String>>(
78        &self,
79        error_name: S,
80        error_msg: Option<String>,
81    ) -> crate::message_builder::MarshalledMessage {
82        let mut err_resp = crate::message_builder::MarshalledMessage {
83            typ: MessageType::Reply,
84            dynheader: DynamicHeader {
85                interface: None,
86                member: None,
87                object: None,
88                destination: self.sender.clone(),
89                serial: None,
90                num_fds: None,
91                sender: None,
92                signature: None,
93                response_serial: self.serial,
94                error_name: Some(error_name.into()),
95            },
96            flags: 0,
97            body: crate::message_builder::MarshalledMessageBody::new(),
98        };
99        if let Some(text) = error_msg {
100            err_resp.body.push_param(text).unwrap();
101        }
102        err_resp
103    }
104    /// Make a correctly addressed response with the correct response serial
105    pub fn make_response(&self) -> crate::message_builder::MarshalledMessage {
106        crate::message_builder::MarshalledMessage {
107            typ: MessageType::Reply,
108            dynheader: DynamicHeader {
109                interface: None,
110                member: None,
111                object: None,
112                destination: self.sender.clone(),
113                serial: None,
114                num_fds: None,
115                sender: None,
116                signature: None,
117                response_serial: self.serial,
118                error_name: None,
119            },
120            flags: 0,
121            body: crate::message_builder::MarshalledMessageBody::new(),
122        }
123    }
124}
125
126/// Starting point for new messages. Create either a call or a signal
127#[derive(Default)]
128pub struct MessageBuilder {
129    msg: MarshalledMessage,
130}
131
132/// Created by MessageBuilder::call. Use it to make a new call to a service
133pub struct CallBuilder {
134    msg: MarshalledMessage,
135}
136
137/// Created by MessageBuilder::signal. Use it to make a new signal
138pub struct SignalBuilder {
139    msg: MarshalledMessage,
140}
141
142impl MessageBuilder {
143    /// New messagebuilder with the default native byteorder
144    pub fn new() -> MessageBuilder {
145        MessageBuilder {
146            msg: MarshalledMessage::new(),
147        }
148    }
149
150    /// New messagebuilder with a chosen byteorder
151    pub fn with_byteorder(b: ByteOrder) -> MessageBuilder {
152        MessageBuilder {
153            msg: MarshalledMessage::with_byteorder(b),
154        }
155    }
156
157    pub fn call<S: Into<String>>(mut self, member: S) -> CallBuilder {
158        self.msg.typ = MessageType::Call;
159        self.msg.dynheader.member = Some(member.into());
160        CallBuilder { msg: self.msg }
161    }
162    pub fn signal<S1, S2, S3>(mut self, interface: S1, member: S2, object: S3) -> SignalBuilder
163    where
164        S1: Into<String>,
165        S2: Into<String>,
166        S3: Into<String>,
167    {
168        self.msg.typ = MessageType::Signal;
169        self.msg.dynheader.member = Some(member.into());
170        self.msg.dynheader.interface = Some(interface.into());
171        self.msg.dynheader.object = Some(object.into());
172        SignalBuilder { msg: self.msg }
173    }
174}
175
176impl CallBuilder {
177    pub fn on<S: Into<String>>(mut self, object_path: S) -> Self {
178        self.msg.dynheader.object = Some(object_path.into());
179        self
180    }
181
182    pub fn with_interface<S: Into<String>>(mut self, interface: S) -> Self {
183        self.msg.dynheader.interface = Some(interface.into());
184        self
185    }
186
187    pub fn at<S: Into<String>>(mut self, destination: S) -> Self {
188        self.msg.dynheader.destination = Some(destination.into());
189        self
190    }
191
192    pub fn build(self) -> MarshalledMessage {
193        self.msg
194    }
195}
196
197impl SignalBuilder {
198    pub fn to<S: Into<String>>(mut self, destination: S) -> Self {
199        self.msg.dynheader.destination = Some(destination.into());
200        self
201    }
202
203    pub fn build(self) -> MarshalledMessage {
204        self.msg
205    }
206}
207
208/// Message received by a connection or in preparation before being sent over a connection.
209///
210/// This represents a message while it is being built before it is sent over the connection.
211/// The body accepts everything that implements the Marshal trait (e.g. all basic types, strings, slices, Hashmaps,.....)
212/// And you can of course write an Marshal impl for your own datastructures. See the doc on the Marshal trait what you have
213/// to look out for when doing this though.
214#[derive(Debug)]
215pub struct MarshalledMessage {
216    pub body: MarshalledMessageBody,
217
218    pub dynheader: DynamicHeader,
219
220    pub typ: MessageType,
221    pub flags: u8,
222}
223
224impl Default for MarshalledMessage {
225    fn default() -> Self {
226        Self::new()
227    }
228}
229
230impl MarshalledMessage {
231    pub fn get_buf(&self) -> &[u8] {
232        &self.body.buf
233    }
234    pub fn get_sig(&self) -> &str {
235        &self.body.sig
236    }
237
238    /// New message with the default native byteorder
239    pub fn new() -> Self {
240        MarshalledMessage {
241            typ: MessageType::Invalid,
242            dynheader: DynamicHeader::default(),
243
244            flags: 0,
245            body: MarshalledMessageBody::new(),
246        }
247    }
248
249    /// New messagebody with a chosen byteorder
250    pub fn with_byteorder(b: ByteOrder) -> Self {
251        MarshalledMessage {
252            typ: MessageType::Invalid,
253            dynheader: DynamicHeader::default(),
254
255            flags: 0,
256            body: MarshalledMessageBody::with_byteorder(b),
257        }
258    }
259
260    /// Reserves space for `additional` bytes in the internal buffer. This is useful to reduce the amount of allocations done while marshalling,
261    /// if you can predict somewhat accuratly how many bytes you will be marshalling.
262    pub fn reserve(&mut self, additional: usize) {
263        self.body.reserve(additional)
264    }
265
266    pub fn unmarshall_all<'a, 'e>(self) -> Result<message::Message<'a, 'e>, UnmarshalError> {
267        let params = if self.body.sig.is_empty() {
268            vec![]
269        } else {
270            let sigs: Vec<_> = crate::signature::Type::parse_description(&self.body.sig)?;
271
272            let (_, params) = crate::wire::unmarshal::unmarshal_body(
273                self.body.byteorder,
274                &sigs,
275                &self.body.buf,
276                &self.body.raw_fds,
277                0,
278            )?;
279            params
280        };
281        Ok(message::Message {
282            dynheader: self.dynheader,
283            params,
284            typ: self.typ,
285            flags: self.flags,
286            raw_fds: self.body.raw_fds,
287        })
288    }
289}
290/// The body accepts everything that implements the Marshal trait (e.g. all basic types, strings, slices, Hashmaps,.....)
291/// And you can of course write an Marshal impl for your own datastrcutures
292#[derive(Debug)]
293pub struct MarshalledMessageBody {
294    pub(crate) buf: Vec<u8>,
295
296    // out of band data
297    pub(crate) raw_fds: Vec<crate::wire::UnixFd>,
298
299    sig: SignatureBuffer,
300    pub(crate) byteorder: ByteOrder,
301}
302
303impl Default for MarshalledMessageBody {
304    fn default() -> Self {
305        Self::new()
306    }
307}
308
309/// Helper function you might need, if the dbus API you use has Variants somewhere inside nested structures. If the the
310/// API has a Variant at the top-level you can use MarshalledMessageBody::push_variant.
311pub fn marshal_as_variant<P: Marshal>(
312    p: P,
313    byteorder: ByteOrder,
314    buf: &mut Vec<u8>,
315    fds: &mut Vec<crate::wire::UnixFd>,
316) -> Result<(), MarshalError> {
317    let mut ctx = MarshalContext {
318        fds,
319        buf,
320        byteorder,
321    };
322    let ctx = &mut ctx;
323
324    // get signature string and write it to the buffer
325    let mut sig_str = SignatureBuffer::new();
326    P::sig_str(&mut sig_str);
327    let sig = crate::wire::SignatureWrapper::new(sig_str)?;
328    sig.marshal(ctx)?;
329
330    // the write the value to the buffer
331    p.marshal(ctx)?;
332    Ok(())
333}
334
335impl MarshalledMessageBody {
336    /// New messagebody with the default native byteorder
337    pub fn new() -> Self {
338        MarshalledMessageBody {
339            buf: Vec::new(),
340            raw_fds: Vec::new(),
341            sig: SignatureBuffer::new(),
342            byteorder: ByteOrder::NATIVE,
343        }
344    }
345
346    /// New messagebody with a chosen byteorder
347    pub fn with_byteorder(b: ByteOrder) -> Self {
348        MarshalledMessageBody {
349            buf: Vec::new(),
350            raw_fds: Vec::new(),
351            sig: SignatureBuffer::new(),
352            byteorder: b,
353        }
354    }
355
356    pub fn from_parts(
357        buf: Vec<u8>,
358        raw_fds: Vec<crate::wire::UnixFd>,
359        sig: String,
360        byteorder: ByteOrder,
361    ) -> Self {
362        let sig = SignatureBuffer::from_string(sig);
363        Self {
364            buf,
365            raw_fds,
366            sig,
367            byteorder,
368        }
369    }
370    /// Get a clone of all the `UnixFd`s in the body.
371    ///
372    /// Some of the `UnixFd`s may already have their `RawFd`s taken.
373    pub fn get_fds(&self) -> Vec<UnixFd> {
374        self.raw_fds.clone()
375    }
376    /// Clears the buffer and signature but holds on to the memory allocations. You can now start pushing new
377    /// params as if this were a new message. This allows to reuse the OutMessage for the same dbus-message with different
378    /// parameters without allocating the buffer every time.
379    pub fn reset(&mut self) {
380        self.sig.clear();
381        self.buf.clear();
382    }
383
384    /// Reserves space for `additional` bytes in the internal buffer. This is useful to reduce the amount of allocations done while marshalling,
385    /// if you can predict somewhat accuratly how many bytes you will be marshalling.
386    pub fn reserve(&mut self, additional: usize) {
387        self.buf.reserve(additional)
388    }
389
390    /// Push a Param with the old nested enum/struct approach. This is still supported for the case that in some corner cases
391    /// the new trait/type based API does not work.
392    pub fn push_old_param(&mut self, p: &crate::params::Param) -> Result<(), MarshalError> {
393        let mut ctx = MarshalContext {
394            buf: &mut self.buf,
395            fds: &mut self.raw_fds,
396            byteorder: self.byteorder,
397        };
398        let ctx = &mut ctx;
399        crate::wire::marshal::container::marshal_param(p, ctx)?;
400        p.sig().to_str(self.sig.to_string_mut());
401        Ok(())
402    }
403
404    /// Convenience function to call push_old_param on a slice of Param
405    pub fn push_old_params(&mut self, ps: &[crate::params::Param]) -> Result<(), MarshalError> {
406        for p in ps {
407            self.push_old_param(p)?;
408        }
409        Ok(())
410    }
411    fn create_ctx(&mut self) -> MarshalContext {
412        MarshalContext {
413            buf: &mut self.buf,
414            fds: &mut self.raw_fds,
415            byteorder: self.byteorder,
416        }
417    }
418
419    /// Append something that is Marshal to the message body
420    pub fn push_param<P: Marshal>(&mut self, p: P) -> Result<(), MarshalError> {
421        let mut ctx = self.create_ctx();
422        p.marshal(&mut ctx)?;
423        P::sig_str(&mut self.sig);
424        Ok(())
425    }
426
427    /// execute some amount of push calls and if any of them fails, reset the body
428    // to the state it was in before the push calls where executed
429    fn push_mult_helper<F>(&mut self, push_calls: F) -> Result<(), MarshalError>
430    where
431        F: FnOnce(&mut MarshalledMessageBody) -> Result<(), MarshalError>,
432    {
433        let sig_len = self.sig.len();
434        let buf_len = self.buf.len();
435        let fds_len = self.raw_fds.len();
436
437        match push_calls(self) {
438            Ok(ret) => Ok(ret),
439            Err(e) => {
440                // reset state to before any of the push calls happened
441                self.sig.truncate(sig_len)?;
442                self.buf.truncate(buf_len);
443                self.raw_fds.truncate(fds_len);
444                Err(e)
445            }
446        }
447    }
448
449    /// Append two things that are Marshal to the message body
450    pub fn push_param2<P1: Marshal, P2: Marshal>(
451        &mut self,
452        p1: P1,
453        p2: P2,
454    ) -> Result<(), MarshalError> {
455        self.push_mult_helper(move |msg: &mut Self| {
456            msg.push_param(p1)?;
457            msg.push_param(p2)
458        })
459    }
460
461    /// Append three things that are Marshal to the message body
462    pub fn push_param3<P1: Marshal, P2: Marshal, P3: Marshal>(
463        &mut self,
464        p1: P1,
465        p2: P2,
466        p3: P3,
467    ) -> Result<(), MarshalError> {
468        self.push_mult_helper(move |msg: &mut Self| {
469            msg.push_param(p1)?;
470            msg.push_param(p2)?;
471            msg.push_param(p3)
472        })
473    }
474
475    /// Append four things that are Marshal to the message body
476    pub fn push_param4<P1: Marshal, P2: Marshal, P3: Marshal, P4: Marshal>(
477        &mut self,
478        p1: P1,
479        p2: P2,
480        p3: P3,
481        p4: P4,
482    ) -> Result<(), MarshalError> {
483        self.push_mult_helper(move |msg: &mut Self| {
484            msg.push_param(p1)?;
485            msg.push_param(p2)?;
486            msg.push_param(p3)?;
487            msg.push_param(p4)
488        })
489    }
490
491    /// Append five things that are Marshal to the message body
492    pub fn push_param5<P1: Marshal, P2: Marshal, P3: Marshal, P4: Marshal, P5: Marshal>(
493        &mut self,
494        p1: P1,
495        p2: P2,
496        p3: P3,
497        p4: P4,
498        p5: P5,
499    ) -> Result<(), MarshalError> {
500        self.push_mult_helper(move |msg: &mut Self| {
501            msg.push_param(p1)?;
502            msg.push_param(p2)?;
503            msg.push_param(p3)?;
504            msg.push_param(p4)?;
505            msg.push_param(p5)
506        })
507    }
508
509    /// Append any number of things that have the same type that is Marshal to the message body
510    pub fn push_params<P: Marshal>(&mut self, params: &[P]) -> Result<(), MarshalError> {
511        for p in params {
512            self.push_param(p)?;
513        }
514        Ok(())
515    }
516
517    /// Append something that is Marshal to the body but use a dbus Variant in the signature. This is necessary for some APIs
518    pub fn push_variant<P: Marshal>(&mut self, p: P) -> Result<(), MarshalError> {
519        self.sig.push_static("v");
520        let mut ctx = self.create_ctx();
521        p.marshal_as_variant(&mut ctx)
522    }
523    /// Validate the all the marshalled elements of the body.
524    pub fn validate(&self) -> Result<(), UnmarshalError> {
525        if self.sig.is_empty() && self.buf.is_empty() {
526            return Ok(());
527        }
528        let types = crate::signature::Type::parse_description(&self.sig)?;
529        let mut used = 0;
530        for typ in types {
531            used += validate_raw::validate_marshalled(self.byteorder, used, &self.buf, &typ)
532                .map_err(|(_, e)| e)?;
533        }
534        if used == self.buf.len() {
535            Ok(())
536        } else {
537            Err(UnmarshalError::NotAllBytesUsed)
538        }
539    }
540    /// Create a parser to retrieve parameters from the body.
541    #[inline]
542    pub fn parser(&self) -> MessageBodyParser {
543        MessageBodyParser::new(self)
544    }
545}
546
547#[test]
548fn test_marshal_trait() {
549    let mut body = MarshalledMessageBody::new();
550    let bytes: &[&[_]] = &[&[4u64]];
551    body.push_param(bytes).unwrap();
552
553    assert_eq!(
554        vec![12, 0, 0, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0],
555        body.buf
556    );
557    assert_eq!(body.sig.as_str(), "aat");
558
559    let mut body = MarshalledMessageBody::new();
560    let mut map = std::collections::HashMap::new();
561    map.insert("a", 4u32);
562
563    body.push_param(&map).unwrap();
564    assert_eq!(
565        vec![12, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, b'a', 0, 0, 0, 4, 0, 0, 0,],
566        body.buf
567    );
568    assert_eq!(body.sig.as_str(), "a{su}");
569
570    let mut body = MarshalledMessageBody::new();
571    body.push_param((11u64, "str", true)).unwrap();
572    assert_eq!(body.sig.as_str(), "(tsb)");
573    assert_eq!(
574        vec![11, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, b's', b't', b'r', 0, 1, 0, 0, 0,],
575        body.buf
576    );
577
578    struct MyStruct {
579        x: u64,
580        y: String,
581    }
582
583    use crate::wire::marshal::traits::Signature;
584    use crate::wire::marshal::MarshalContext;
585    impl Signature for &MyStruct {
586        fn signature() -> crate::signature::Type {
587            crate::signature::Type::Container(crate::signature::Container::Struct(
588                crate::signature::StructTypes::new(vec![u64::signature(), String::signature()])
589                    .unwrap(),
590            ))
591        }
592
593        fn alignment() -> usize {
594            8
595        }
596        #[inline]
597        fn sig_str(s_buf: &mut crate::wire::marshal::traits::SignatureBuffer) {
598            s_buf.push_static("(ts)")
599        }
600        fn has_sig(sig: &str) -> bool {
601            sig == "(ts)"
602        }
603    }
604    impl Marshal for &MyStruct {
605        fn marshal(&self, ctx: &mut MarshalContext) -> Result<(), MarshalError> {
606            // always align to 8
607            ctx.align_to(8);
608            self.x.marshal(ctx)?;
609            self.y.marshal(ctx)?;
610            Ok(())
611        }
612    }
613
614    let mut body = MarshalledMessageBody::new();
615    body.push_param(&MyStruct {
616        x: 100,
617        y: "A".to_owned(),
618    })
619    .unwrap();
620    assert_eq!(body.sig.as_str(), "(ts)");
621    assert_eq!(
622        vec![100, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, b'A', 0,],
623        body.buf
624    );
625
626    let mut body = MarshalledMessageBody::new();
627    let emptymap: std::collections::HashMap<&str, u32> = std::collections::HashMap::new();
628    let mut map = std::collections::HashMap::new();
629    let mut map2 = std::collections::HashMap::new();
630    map.insert("a", 4u32);
631    map2.insert("a", &map);
632
633    body.push_param(&map2).unwrap();
634    body.push_param(&emptymap).unwrap();
635    assert_eq!(body.sig.as_str(), "a{sa{su}}a{su}");
636    assert_eq!(
637        vec![
638            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,
639            0, b'a', 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0
640        ],
641        body.buf
642    );
643
644    // try to unmarshal stuff
645    let mut body_iter = MessageBodyParser::new(&body);
646
647    // first try some stuff that has the wrong signature
648    type WrongNestedDict =
649        std::collections::HashMap<String, std::collections::HashMap<String, u64>>;
650    assert_eq!(
651        body_iter.get::<WrongNestedDict>().err().unwrap(),
652        UnmarshalError::WrongSignature
653    );
654    type WrongStruct = (u64, i32, String);
655    assert_eq!(
656        body_iter.get::<WrongStruct>().err().unwrap(),
657        UnmarshalError::WrongSignature
658    );
659
660    // the get the correct type and make sure the content is correct
661    type NestedDict = std::collections::HashMap<String, std::collections::HashMap<String, u32>>;
662    let newmap2: NestedDict = body_iter.get().unwrap();
663    assert_eq!(newmap2.len(), 1);
664    assert_eq!(newmap2.get("a").unwrap().len(), 1);
665    assert_eq!(*newmap2.get("a").unwrap().get("a").unwrap(), 4);
666
667    // again try some stuff that has the wrong signature
668    assert_eq!(
669        body_iter.get::<WrongNestedDict>().err().unwrap(),
670        UnmarshalError::WrongSignature
671    );
672    assert_eq!(
673        body_iter.get::<WrongStruct>().err().unwrap(),
674        UnmarshalError::WrongSignature
675    );
676
677    // get the empty map next
678    let newemptymap: std::collections::HashMap<&str, u32> = body_iter.get().unwrap();
679    assert_eq!(newemptymap.len(), 0);
680
681    // test get2()
682    let mut body_iter = body.parser();
683    assert_eq!(
684        body_iter.get2::<NestedDict, u16>().unwrap_err(),
685        UnmarshalError::WrongSignature
686    );
687    assert_eq!(
688        body_iter
689            .get3::<NestedDict, std::collections::HashMap<&str, u32>, u32>()
690            .unwrap_err(),
691        UnmarshalError::EndOfMessage
692    );
693
694    // test to make sure body_iter is left unchanged from last failure and the map is
695    // pulled out identically from above
696    let (newmap2, newemptymap): (NestedDict, std::collections::HashMap<&str, u32>) =
697        body_iter.get2().unwrap();
698    // repeat assertions from above
699    assert_eq!(newmap2.len(), 1);
700    assert_eq!(newmap2.get("a").unwrap().len(), 1);
701    assert_eq!(*newmap2.get("a").unwrap().get("a").unwrap(), 4);
702    assert_eq!(newemptymap.len(), 0);
703    assert_eq!(
704        body_iter.get::<u16>().unwrap_err(),
705        UnmarshalError::EndOfMessage
706    );
707
708    // test mixed get() and get_param()
709    let mut body_iter = body.parser();
710
711    // test to make sure body_iter is left unchanged from last failure and the map is
712    // pulled out identically from above
713    let newmap2: NestedDict = body_iter.get().unwrap();
714    let newemptymap = body_iter.get_param().unwrap();
715    // repeat assertions from above
716    assert_eq!(newmap2.len(), 1);
717    assert_eq!(newmap2.get("a").unwrap().len(), 1);
718    assert_eq!(*newmap2.get("a").unwrap().get("a").unwrap(), 4);
719
720    use crate::params::Container;
721    use crate::params::Param;
722    match newemptymap {
723        Param::Container(Container::Dict(dict)) => {
724            assert_eq!(dict.map.len(), 0);
725            assert_eq!(dict.key_sig, crate::signature::Base::String);
726            assert_eq!(
727                dict.value_sig,
728                crate::signature::Type::Base(crate::signature::Base::Uint32)
729            );
730        }
731        _ => panic!("Expected to get a dict"),
732    }
733    assert_eq!(
734        body_iter.get::<u16>().unwrap_err(),
735        UnmarshalError::EndOfMessage
736    );
737}
738
739use crate::wire::unmarshal::traits::Unmarshal;
740/// Iterate over the messages parameters
741///
742/// Because dbus allows for multiple toplevel params without an enclosing struct, this provides a simple Iterator (sadly not std::iterator::Iterator, since the types
743/// of the parameters can be different)
744/// that you can use to get the params one by one, calling `get::<T>` until you have obtained all the parameters.
745/// 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
746/// fit the current one, it will return an Error::WrongSignature, but you can safely try other types, the iterator stays valid.
747#[derive(Debug)]
748pub struct MessageBodyParser<'body> {
749    buf_idx: usize,
750    sig_idx: usize,
751    body: &'body MarshalledMessageBody,
752}
753
754impl<'fds, 'body: 'fds> MessageBodyParser<'body> {
755    pub fn new(body: &'body MarshalledMessageBody) -> Self {
756        Self {
757            buf_idx: 0,
758            sig_idx: 0,
759            body,
760        }
761    }
762
763    #[inline(always)]
764    fn sig_iter(&self) -> SignatureIter<'body> {
765        SignatureIter::new_at_idx(self.body.sig.as_str(), self.sig_idx)
766    }
767
768    /// Get the next params signature (if any are left)
769    #[inline(always)]
770    pub fn get_next_sig(&self) -> Option<&'body str> {
771        self.sig_iter().next()
772    }
773
774    #[inline(always)]
775    pub fn sigs_left(&self) -> usize {
776        self.sig_iter().count()
777    }
778
779    /// Get the next param, use get::<TYPE> to specify what type you expect. For example `let s = parser.get::<String>()?;`
780    /// This checks if there are params left in the message and if the type you requested fits the signature of the message.
781    pub fn get<T: Unmarshal<'body, 'fds>>(&mut self) -> Result<T, UnmarshalError> {
782        if let Some(expected_sig) = self.get_next_sig() {
783            if !T::has_sig(expected_sig) {
784                return Err(UnmarshalError::WrongSignature);
785            }
786
787            let mut ctx = UnmarshalContext {
788                byteorder: self.body.byteorder,
789                buf: &self.body.buf,
790                offset: self.buf_idx,
791                fds: &self.body.raw_fds,
792            };
793            match T::unmarshal(&mut ctx) {
794                Ok((bytes, res)) => {
795                    self.buf_idx += bytes;
796                    self.sig_idx += expected_sig.len();
797                    Ok(res)
798                }
799                Err(e) => Err(e),
800            }
801        } else {
802            Err(UnmarshalError::EndOfMessage)
803        }
804    }
805    /// Perform error handling for `get2(), get3()...` if `get_calls` fails.
806    fn get_mult_helper<T, F>(&mut self, count: usize, get_calls: F) -> Result<T, UnmarshalError>
807    where
808        F: FnOnce(&mut Self) -> Result<T, UnmarshalError>,
809    {
810        if count > self.sigs_left() {
811            return Err(UnmarshalError::EndOfMessage);
812        }
813        let start_sig_idx = self.sig_idx;
814        let start_buf_idx = self.buf_idx;
815        match get_calls(self) {
816            Ok(ret) => Ok(ret),
817            Err(err) => {
818                self.sig_idx = start_sig_idx;
819                self.buf_idx = start_buf_idx;
820                Err(err)
821            }
822        }
823    }
824
825    /// Get the next two params, use get2::<TYPE, TYPE> to specify what type you expect. For example `let s = parser.get2::<String, i32>()?;`
826    /// This checks if there are params left in the message and if the type you requested fits the signature of the message.
827    pub fn get2<T1, T2>(&mut self) -> Result<(T1, T2), UnmarshalError>
828    where
829        T1: Unmarshal<'body, 'fds>,
830        T2: Unmarshal<'body, 'fds>,
831    {
832        let get_calls = |parser: &mut Self| {
833            let ret1 = parser.get()?;
834            let ret2 = parser.get()?;
835            Ok((ret1, ret2))
836        };
837        self.get_mult_helper(2, get_calls)
838    }
839
840    /// 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>()?;`
841    /// This checks if there are params left in the message and if the type you requested fits the signature of the message.
842    pub fn get3<T1, T2, T3>(&mut self) -> Result<(T1, T2, T3), UnmarshalError>
843    where
844        T1: Unmarshal<'body, 'fds>,
845        T2: Unmarshal<'body, 'fds>,
846        T3: Unmarshal<'body, 'fds>,
847    {
848        let get_calls = |parser: &mut Self| {
849            let ret1 = parser.get()?;
850            let ret2 = parser.get()?;
851            let ret3 = parser.get()?;
852            Ok((ret1, ret2, ret3))
853        };
854        self.get_mult_helper(3, get_calls)
855    }
856
857    /// 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>()?;`
858    /// This checks if there are params left in the message and if the type you requested fits the signature of the message.
859    pub fn get4<T1, T2, T3, T4>(&mut self) -> Result<(T1, T2, T3, T4), UnmarshalError>
860    where
861        T1: Unmarshal<'body, 'fds>,
862        T2: Unmarshal<'body, 'fds>,
863        T3: Unmarshal<'body, 'fds>,
864        T4: Unmarshal<'body, 'fds>,
865    {
866        let get_calls = |parser: &mut Self| {
867            let ret1 = parser.get()?;
868            let ret2 = parser.get()?;
869            let ret3 = parser.get()?;
870            let ret4 = parser.get()?;
871            Ok((ret1, ret2, ret3, ret4))
872        };
873        self.get_mult_helper(4, get_calls)
874    }
875
876    /// 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>()?;`
877    /// This checks if there are params left in the message and if the type you requested fits the signature of the message.
878    pub fn get5<T1, T2, T3, T4, T5>(&mut self) -> Result<(T1, T2, T3, T4, T5), UnmarshalError>
879    where
880        T1: Unmarshal<'body, 'fds>,
881        T2: Unmarshal<'body, 'fds>,
882        T3: Unmarshal<'body, 'fds>,
883        T4: Unmarshal<'body, 'fds>,
884        T5: Unmarshal<'body, 'fds>,
885    {
886        let get_calls = |parser: &mut Self| {
887            let ret1 = parser.get()?;
888            let ret2 = parser.get()?;
889            let ret3 = parser.get()?;
890            let ret4 = parser.get()?;
891            let ret5 = parser.get()?;
892            Ok((ret1, ret2, ret3, ret4, ret5))
893        };
894        self.get_mult_helper(5, get_calls)
895    }
896
897    /// Get the next (old_style) param.
898    /// This checks if there are params left in the message and if the type you requested fits the signature of the message.
899    pub fn get_param(&mut self) -> Result<crate::params::Param, UnmarshalError> {
900        if let Some(sig_str) = self.get_next_sig() {
901            let mut ctx = UnmarshalContext {
902                byteorder: self.body.byteorder,
903                buf: &self.body.buf,
904                offset: self.buf_idx,
905                fds: &self.body.raw_fds,
906            };
907
908            let sig = &crate::signature::Type::parse_description(sig_str).unwrap()[0];
909
910            match crate::wire::unmarshal::container::unmarshal_with_sig(sig, &mut ctx) {
911                Ok((bytes, res)) => {
912                    self.buf_idx += bytes;
913                    self.sig_idx += sig_str.len();
914                    Ok(res)
915                }
916                Err(e) => Err(e),
917            }
918        } else {
919            Err(UnmarshalError::EndOfMessage)
920        }
921    }
922}
923
924#[cfg(test)]
925mod tests {
926    #[test]
927    fn parser_get() {
928        use crate::wire::errors::UnmarshalError;
929
930        let mut sig = super::MessageBuilder::new()
931            .signal("io.killingspark", "Signal", "/io/killingspark/Signaler")
932            .build();
933
934        sig.body.push_param3(100u32, 200i32, "ABCDEFGH").unwrap();
935
936        let mut parser = sig.body.parser();
937        assert_eq!(parser.get(), Ok(100u32));
938        assert_eq!(parser.get(), Ok(200i32));
939        assert_eq!(parser.get(), Ok("ABCDEFGH"));
940        assert_eq!(parser.get::<String>(), Err(UnmarshalError::EndOfMessage));
941
942        let mut parser = sig.body.parser();
943        assert_eq!(parser.get2(), Ok((100u32, 200i32)));
944        assert_eq!(parser.get(), Ok("ABCDEFGH"));
945        assert_eq!(parser.get::<String>(), Err(UnmarshalError::EndOfMessage));
946
947        let mut parser = sig.body.parser();
948        assert_eq!(parser.get3(), Ok((100u32, 200i32, "ABCDEFGH")));
949        assert_eq!(parser.get::<String>(), Err(UnmarshalError::EndOfMessage));
950
951        let mut sig = super::MessageBuilder::new()
952            .signal("io.killingspark", "Signal", "/io/killingspark/Signaler")
953            .build();
954
955        sig.body.push_param((100u32, 200i32, "ABCDEFGH")).unwrap();
956        sig.body.push_param((100u32, 200i32, "ABCDEFGH")).unwrap();
957        sig.body.push_param((100u32, 200i32, "ABCDEFGH")).unwrap();
958
959        let mut parser = sig.body.parser();
960        assert!(parser.get::<(u32, i32, &str)>().is_ok());
961        assert!(parser.get2::<(u32, i32, &str), (u32, i32, &str)>().is_ok());
962    }
963}