rustbus/wire/unmarshal/
traits.rs

1//! Provides the Unmarshal trait and the implementations for the base types
2
3use crate::wire::marshal::traits::Signature;
4use crate::wire::unmarshal;
5use crate::wire::unmarshal::UnmarshalContext;
6
7// these contain the implementations
8mod base;
9mod container;
10pub use base::*;
11pub use container::*;
12
13/// This trait has to be supported to get parameters ergonomically out of a MarshalledMessage.
14/// There are implementations for the base types, Vecs, Hashmaps, and tuples of up to 5 elements
15/// if the contained types are Unmarshal.
16/// If you deal with basic messages, this should cover all your needs and you dont need to implement this type for
17/// your own types.
18///
19/// There is a crate (rustbus_derive) for deriving Unmarshal impls with #[derive(rustbus_derive::Marshal)]. This should work for most of your needs.
20/// You can of course derive Signature as well.
21///
22/// If there are special needs, you can implement Unmarshal for your own structs:
23///
24/// # Implementing for your own structs
25/// You can of course add your own implementations for types.
26/// For this to work properly the signature must be correct and you need to report all bytes you consumed
27/// in the T::unmarshal(...) call. THIS INCLUDES PADDING.
28///
29/// Typically your code should look like this:
30/// ```rust
31/// struct MyStruct{ mycoolint: u64}
32/// use rustbus::wire::marshal::traits::Signature;
33/// use rustbus::signature;
34/// use rustbus::wire::unmarshal;
35/// use rustbus::wire::unmarshal::UnmarshalContext;
36/// use rustbus::wire::unmarshal::traits::Unmarshal;
37/// use rustbus::wire::unmarshal::UnmarshalResult;
38/// use rustbus::wire::marshal::traits::SignatureBuffer;
39/// use rustbus::wire::util;
40/// use rustbus::ByteOrder;
41///
42/// impl Signature for MyStruct {
43///     fn signature() -> signature::Type {
44///         signature::Type::Container(signature::Container::Struct(signature::StructTypes::new(vec![
45///             u64::signature(),
46///         ]).unwrap()))
47///     }
48///
49///     fn alignment() -> usize {
50///         8
51///     }
52///     fn sig_str(s_buf: &mut SignatureBuffer) {
53///         s_buf.push_static("(ts)");
54///     }
55///     fn has_sig(sig: &str) -> bool {
56///         sig == "(ts)"
57///     }
58/// }
59///
60/// impl<'buf, 'fds> Unmarshal<'buf, 'fds> for MyStruct {
61///    fn unmarshal(ctx: &mut UnmarshalContext<'fds, 'buf>) -> unmarshal::UnmarshalResult<Self> {
62///         let start_offset = ctx.offset;
63///         // check that we are aligned properly!
64///         // This is necessary at the start of each struct! They need to be aligned to 8 bytes!
65///         let padding = ctx.align_to(Self::alignment())?;
66///
67///         // decode some stuff and adjust offset
68///         let (bytes, mycoolint) = u64::unmarshal(ctx)?;
69///         
70///         // some more decoding if the struct had more fields
71///         // ....
72///         
73///         //then report the total bytes used by unmarshalling this type (INCLUDING padding at the beginning!):
74///         let total_bytes = ctx.offset - start_offset;
75///         Ok((total_bytes, MyStruct{mycoolint}))
76///     }
77/// }
78/// ```
79///
80/// This is of course just an example, this could be solved by using
81/// ```rust,ignore
82/// let (bytes, mycoolint) =  <(u64,) as Unmarshal>::unmarshal(...)
83/// ```
84///
85/// ## Cool things you can do
86/// If the message contains some form of secondary marshalling, of another format, you can do this here too, instead of copying the bytes
87/// array around before doing the secondary unmarshalling. Just keep in mind that you have to report the accurate number of bytes used, and not to
88/// use any bytes in the message, not belonging to that byte array
89///
90/// As an example, lets assume your message contains a byte-array that is actually json data. Then you can use serde_json to unmarshal that array
91/// directly here without having to do a separate step for that.
92/// ```rust
93/// use rustbus::Unmarshal;
94/// use rustbus::wire::unmarshal::UnmarshalResult;
95/// use rustbus::wire::unmarshal::UnmarshalContext;
96/// use rustbus::wire::marshal::traits::Signature;
97/// use rustbus::wire::marshal::traits::SignatureBuffer;
98/// use rustbus::signature;
99///
100/// struct MyStruct{ mycoolint: u64}
101/// impl Signature for MyStruct {
102///     fn signature() -> signature::Type {
103///         signature::Type::Container(signature::Container::Struct(signature::StructTypes::new(vec![
104///             u64::signature(),
105///         ]).unwrap()))
106///     }
107///
108///     fn alignment() -> usize {
109///         8
110///     }
111///     fn sig_str(s_buf: &mut SignatureBuffer) {
112///         s_buf.push_static("(ts)");
113///     }
114///     fn has_sig(sig: &str) -> bool {
115///         sig == "(ts)"
116///     }
117/// }
118///
119/// fn unmarshal_stuff_from_raw(raw: &[u8]) -> u64 { 0 }
120///
121/// impl<'buf, 'fds> Unmarshal<'buf, 'fds> for MyStruct {
122///    fn unmarshal(ctx: &mut UnmarshalContext<'fds, 'buf>) -> UnmarshalResult<Self> {
123///         let start_offset = ctx.offset;
124///         // check that we are aligned properly
125///         let padding = ctx.align_to(Self::alignment())?;
126///
127///         // get the slice that contains marshalled data, and unmarshal it directly here!
128///         let (bytes, raw_data) = <&[u8] as Unmarshal>::unmarshal(ctx)?;
129///         let unmarshalled_stuff = unmarshal_stuff_from_raw(&raw_data);
130///
131///         //then report the total bytes used by unmarshalling this type (INCLUDING padding at the beginning!):
132///         let total_bytes = ctx.offset - start_offset;
133///         Ok((total_bytes, MyStruct{mycoolint: unmarshalled_stuff}))
134///     }
135/// }
136/// ```
137
138pub trait Unmarshal<'buf, 'fds>: Sized + Signature {
139    fn unmarshal(ctx: &mut UnmarshalContext<'fds, 'buf>) -> unmarshal::UnmarshalResult<Self>;
140}
141
142pub fn unmarshal<'buf, 'fds, T: Unmarshal<'buf, 'fds>>(
143    ctx: &mut UnmarshalContext<'fds, 'buf>,
144) -> unmarshal::UnmarshalResult<T> {
145    T::unmarshal(ctx)
146}
147
148#[cfg(test)]
149mod test {
150    use super::unmarshal;
151    use super::Unmarshal;
152    use super::UnmarshalContext;
153    use super::Variant;
154    use crate::wire::marshal::MarshalContext;
155    use crate::ByteOrder;
156    use crate::Marshal;
157    use crate::Signature;
158
159    #[test]
160    fn test_generic_unmarshal() {
161        let mut fds = Vec::new();
162        let mut buf = Vec::new();
163        let mut ctx = MarshalContext {
164            buf: &mut buf,
165            fds: &mut fds,
166            byteorder: ByteOrder::LittleEndian,
167        };
168        let ctx = &mut ctx;
169
170        // annotate the receiver with a type &str to unmarshal a &str
171        "ABCD".marshal(ctx).unwrap();
172        let _s: &str = unmarshal(&mut UnmarshalContext {
173            buf: &ctx.buf,
174            byteorder: ctx.byteorder,
175            fds: &ctx.fds,
176            offset: 0,
177        })
178        .unwrap()
179        .1;
180
181        // annotate the receiver with a type bool to unmarshal a bool
182        ctx.buf.clear();
183        true.marshal(ctx).unwrap();
184        let _b: bool = unmarshal(&mut UnmarshalContext {
185            buf: &ctx.buf,
186            byteorder: ctx.byteorder,
187            fds: &ctx.fds,
188            offset: 0,
189        })
190        .unwrap()
191        .1;
192
193        // can also use turbofish syntax
194        ctx.buf.clear();
195        0i32.marshal(ctx).unwrap();
196        let _i = unmarshal::<i32>(&mut UnmarshalContext {
197            buf: &ctx.buf,
198            byteorder: ctx.byteorder,
199            fds: &ctx.fds,
200            offset: 0,
201        })
202        .unwrap()
203        .1;
204
205        // No type info on let arg = unmarshal(...) is needed if it can be derived by other means
206        ctx.buf.clear();
207        fn x(_arg: (i32, i32, &str)) {}
208        (0, 0, "ABCD").marshal(ctx).unwrap();
209        let arg = unmarshal(&mut UnmarshalContext {
210            buf: &ctx.buf,
211            byteorder: ctx.byteorder,
212            fds: &ctx.fds,
213            offset: 0,
214        })
215        .unwrap()
216        .1;
217        x(arg);
218    }
219
220    #[test]
221    fn test_unmarshal_byte_array() {
222        use crate::wire::marshal::MarshalContext;
223        use crate::Marshal;
224
225        let mut orig = vec![];
226        for x in 0..1024 {
227            orig.push((x % 255) as u8);
228        }
229
230        let mut fds = Vec::new();
231        let mut buf = Vec::new();
232        let mut ctx = MarshalContext {
233            buf: &mut buf,
234            fds: &mut fds,
235            byteorder: ByteOrder::LittleEndian,
236        };
237        let ctx = &mut ctx;
238
239        orig.marshal(ctx).unwrap();
240        assert_eq!(&ctx.buf[..4], &[0, 4, 0, 0]);
241        assert_eq!(ctx.buf.len(), 1028);
242        let (bytes, unorig) = <&[u8] as Unmarshal>::unmarshal(&mut UnmarshalContext {
243            buf: ctx.buf,
244            fds: ctx.fds,
245            byteorder: ctx.byteorder,
246            offset: 0,
247        })
248        .unwrap();
249        assert_eq!(bytes, orig.len() + 4);
250        assert_eq!(orig, unorig);
251
252        // even slices of slices of u8 work efficiently
253        let mut orig1 = vec![];
254        let mut orig2 = vec![];
255        for x in 0..1024 {
256            orig1.push((x % 255) as u8);
257        }
258        for x in 0..1024 {
259            orig2.push(((x + 4) % 255) as u8);
260        }
261
262        let orig = vec![orig1.as_slice(), orig2.as_slice()];
263
264        ctx.buf.clear();
265        orig.marshal(ctx).unwrap();
266
267        // unorig[x] points into the appropriate region in buf, and unorigs lifetime is bound to buf
268        let (_bytes, unorig) = <Vec<&[u8]> as Unmarshal>::unmarshal(&mut UnmarshalContext {
269            buf: ctx.buf,
270            fds: ctx.fds,
271            byteorder: ctx.byteorder,
272            offset: 0,
273        })
274        .unwrap();
275        assert_eq!(orig, unorig);
276    }
277
278    #[test]
279    fn test_unmarshal_traits() {
280        use crate::wire::marshal::MarshalContext;
281        use crate::Marshal;
282
283        let mut fds = Vec::new();
284        let mut buf = Vec::new();
285        let mut ctx = MarshalContext {
286            buf: &mut buf,
287            fds: &mut fds,
288            byteorder: ByteOrder::LittleEndian,
289        };
290        let ctx = &mut ctx;
291
292        let original = &["a", "b"];
293        original.marshal(ctx).unwrap();
294
295        let (_, v) = Vec::<&str>::unmarshal(&mut UnmarshalContext {
296            buf: ctx.buf,
297            fds: ctx.fds,
298            byteorder: ctx.byteorder,
299            offset: 0,
300        })
301        .unwrap();
302
303        assert_eq!(original, v.as_slice());
304
305        ctx.buf.clear();
306
307        let mut original = std::collections::HashMap::new();
308        original.insert(0u64, "abc");
309        original.insert(1u64, "dce");
310        original.insert(2u64, "fgh");
311
312        original.marshal(ctx).unwrap();
313
314        let (_, map) = std::collections::HashMap::<u64, &str>::unmarshal(&mut UnmarshalContext {
315            buf: ctx.buf,
316            fds: ctx.fds,
317            byteorder: ctx.byteorder,
318            offset: 0,
319        })
320        .unwrap();
321        assert_eq!(original, map);
322
323        ctx.buf.clear();
324
325        let orig = (30u8, true, 100u8, -123i32);
326        orig.marshal(ctx).unwrap();
327        type ST = (u8, bool, u8, i32);
328        let s = ST::unmarshal(&mut UnmarshalContext {
329            buf: ctx.buf,
330            fds: ctx.fds,
331            byteorder: ctx.byteorder,
332            offset: 0,
333        })
334        .unwrap()
335        .1;
336        assert_eq!(orig, s);
337
338        ctx.buf.clear();
339
340        use crate::wire::UnixFd;
341        use crate::wire::{ObjectPath, SignatureWrapper};
342        let orig_fd = UnixFd::new(nix::unistd::dup(1).unwrap());
343        let orig = (
344            ObjectPath::new("/a/b/c").unwrap(),
345            SignatureWrapper::new("ss(aiau)").unwrap(),
346            &orig_fd,
347        );
348        orig.marshal(ctx).unwrap();
349        assert_eq!(
350            ctx.buf,
351            &[
352                6, 0, 0, 0, b'/', b'a', b'/', b'b', b'/', b'c', 0, 8, b's', b's', b'(', b'a', b'i',
353                b'a', b'u', b')', 0, 0, 0, 0, 0, 0, 0, 0
354            ]
355        );
356        let (_, (p, s, _fd)) =
357            <(ObjectPath<String>, SignatureWrapper<&str>, UnixFd) as Unmarshal>::unmarshal(
358                &mut UnmarshalContext {
359                    buf: ctx.buf,
360                    fds: ctx.fds,
361                    byteorder: ctx.byteorder,
362                    offset: 0,
363                },
364            )
365            .unwrap();
366
367        assert_eq!(p.as_ref(), "/a/b/c");
368        assert_eq!(s.as_ref(), "ss(aiau)");
369    }
370
371    #[test]
372    fn test_variant() {
373        use crate::message_builder::MarshalledMessageBody;
374        use crate::params::{Array, Base, Container, Dict, Param, Variant as ParamVariant};
375        use crate::signature::Type;
376        use crate::wire::SignatureWrapper;
377        use std::collections::HashMap;
378
379        // inital test data
380        let params: [(Param, Type); 10] = [
381            (Base::Byte(0x41).into(), u8::signature()),
382            (Base::Int16(-1234).into(), i16::signature()),
383            (Base::Uint16(1234).into(), u16::signature()),
384            (Base::Int32(-1234567).into(), i32::signature()),
385            (Base::Uint32(1234567).into(), u32::signature()),
386            (Base::Int64(-1234568901234).into(), i64::signature()),
387            (Base::Uint64(1234568901234).into(), u64::signature()),
388            (
389                Base::String("Hello world!".to_string()).into(),
390                String::signature(),
391            ),
392            (
393                Base::Signature("sy".to_string()).into(),
394                SignatureWrapper::<String>::signature(),
395            ),
396            (Base::Boolean(true).into(), bool::signature()),
397        ];
398
399        // push initial data as individual variants
400        let mut body = MarshalledMessageBody::new();
401        for param in &params {
402            let cont = Container::Variant(Box::new(ParamVariant {
403                sig: param.1.clone(),
404                value: param.0.clone(),
405            }));
406            body.push_old_param(&Param::Container(cont)).unwrap();
407        }
408
409        // push initial data as Array of variants
410        let var_vec = params
411            .iter()
412            .map(|(param, typ)| {
413                Param::Container(Container::Variant(Box::new(ParamVariant {
414                    sig: typ.clone(),
415                    value: param.clone(),
416                })))
417            })
418            .collect();
419        let vec_param = Param::Container(Container::Array(Array {
420            element_sig: Variant::signature(),
421            values: var_vec,
422        }));
423        body.push_old_param(&vec_param).unwrap();
424
425        // push initial data as Dict of {String,variants}
426        let var_map = params
427            .iter()
428            .enumerate()
429            .map(|(i, (param, typ))| {
430                (
431                    Base::String(format!("{}", i)),
432                    Param::Container(Container::Variant(Box::new(ParamVariant {
433                        sig: typ.clone(),
434                        value: param.clone(),
435                    }))),
436                )
437            })
438            .collect();
439        let map_param = Param::Container(Container::Dict(Dict {
440            key_sig: crate::signature::Base::String,
441            value_sig: Variant::signature(),
442            map: var_map,
443        }));
444        body.push_old_param(&map_param).unwrap();
445
446        // check the individual variants
447        let mut parser = body.parser();
448        assert_eq!(
449            0x41_u8,
450            parser.get::<Variant>().unwrap().get::<u8>().unwrap()
451        );
452        assert_eq!(
453            -1234_i16,
454            parser.get::<Variant>().unwrap().get::<i16>().unwrap()
455        );
456        assert_eq!(
457            1234_u16,
458            parser.get::<Variant>().unwrap().get::<u16>().unwrap()
459        );
460        assert_eq!(
461            -1234567_i32,
462            parser.get::<Variant>().unwrap().get::<i32>().unwrap()
463        );
464        assert_eq!(
465            1234567_u32,
466            parser.get::<Variant>().unwrap().get::<u32>().unwrap()
467        );
468        assert_eq!(
469            -1234568901234_i64,
470            parser.get::<Variant>().unwrap().get::<i64>().unwrap()
471        );
472        assert_eq!(
473            1234568901234_u64,
474            parser.get::<Variant>().unwrap().get::<u64>().unwrap()
475        );
476        assert_eq!(
477            "Hello world!",
478            parser.get::<Variant>().unwrap().get::<&str>().unwrap()
479        );
480        assert_eq!(
481            SignatureWrapper::new("sy").unwrap(),
482            parser.get::<Variant>().unwrap().get().unwrap()
483        );
484        assert_eq!(
485            true,
486            parser.get::<Variant>().unwrap().get::<bool>().unwrap()
487        );
488
489        // check Array of variants
490        let var_vec: Vec<Variant> = parser.get().unwrap();
491        assert_eq!(0x41_u8, var_vec[0].get::<u8>().unwrap());
492        assert_eq!(-1234_i16, var_vec[1].get::<i16>().unwrap());
493        assert_eq!(1234_u16, var_vec[2].get::<u16>().unwrap());
494        assert_eq!(-1234567_i32, var_vec[3].get::<i32>().unwrap());
495        assert_eq!(1234567_u32, var_vec[4].get::<u32>().unwrap());
496        assert_eq!(-1234568901234_i64, var_vec[5].get::<i64>().unwrap());
497        assert_eq!(1234568901234_u64, var_vec[6].get::<u64>().unwrap());
498        assert_eq!("Hello world!", var_vec[7].get::<&str>().unwrap());
499        assert_eq!(
500            SignatureWrapper::new("sy").unwrap(),
501            var_vec[8].get().unwrap()
502        );
503        assert_eq!(true, var_vec[9].get::<bool>().unwrap());
504
505        // check Dict of {String, variants}
506        let var_map: HashMap<String, Variant> = parser.get().unwrap();
507        assert_eq!(0x41_u8, var_map["0"].get::<u8>().unwrap());
508        assert_eq!(-1234_i16, var_map["1"].get::<i16>().unwrap());
509        assert_eq!(1234_u16, var_map["2"].get::<u16>().unwrap());
510        assert_eq!(-1234567_i32, var_map["3"].get::<i32>().unwrap());
511        assert_eq!(1234567_u32, var_map["4"].get::<u32>().unwrap());
512        assert_eq!(-1234568901234_i64, var_map["5"].get::<i64>().unwrap());
513        assert_eq!(1234568901234_u64, var_map["6"].get::<u64>().unwrap());
514        assert_eq!("Hello world!", var_map["7"].get::<&str>().unwrap());
515        assert_eq!(
516            SignatureWrapper::new("sy").unwrap(),
517            var_map["8"].get().unwrap()
518        );
519        assert_eq!(true, var_map["9"].get::<bool>().unwrap());
520    }
521}