1use byteorder::WriteBytesExt;
2use serde::{ser, Serialize};
3use static_assertions::assert_impl_all;
4use std::{
5 io::{Seek, Write},
6 marker::PhantomData,
7 str,
8};
9
10#[cfg(unix)]
11use std::os::unix::io::RawFd;
12
13#[cfg(feature = "gvariant")]
14use crate::gvariant::{self, Serializer as GVSerializer};
15use crate::{
16 container_depths::ContainerDepths,
17 dbus::{self, Serializer as DBusSerializer},
18 signature_parser::SignatureParser,
19 utils::*,
20 Basic, DynamicType, EncodingContext, EncodingFormat, Error, Result, Signature,
21};
22
23struct NullWriteSeek;
24
25impl Write for NullWriteSeek {
26 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
27 Ok(buf.len())
28 }
29
30 fn flush(&mut self) -> std::io::Result<()> {
31 Ok(())
32 }
33}
34
35impl Seek for NullWriteSeek {
36 fn seek(&mut self, _pos: std::io::SeekFrom) -> std::io::Result<u64> {
37 Ok(std::u64::MAX) // should never read the return value!
38 }
39}
40
41/// Calculate the serialized size of `T`.
42///
43/// # Panics
44///
45/// This function will panic if the value to serialize contains file descriptors. Use
46/// [`serialized_size_fds`] if `T` (potentially) contains FDs.
47///
48/// # Examples
49///
50/// ```
51/// use zvariant::{EncodingContext, serialized_size};
52///
53/// let ctxt = EncodingContext::<byteorder::LE>::new_dbus(0);
54/// let len = serialized_size(ctxt, "hello world").unwrap();
55/// assert_eq!(len, 16);
56///
57/// let len = serialized_size(ctxt, &("hello world!", 42_u64)).unwrap();
58/// assert_eq!(len, 32);
59/// ```
60///
61/// [`serialized_size_fds`]: fn.serialized_size_fds.html
62pub fn serialized_size<B, T: ?Sized>(ctxt: EncodingContext<B>, value: &T) -> Result<usize>
63where
64 B: byteorder::ByteOrder,
65 T: Serialize + DynamicType,
66{
67 let mut null: NullWriteSeek = NullWriteSeek;
68
69 to_writer(&mut null, ctxt, value)
70}
71
72/// Calculate the serialized size of `T` that (potentially) contains FDs.
73///
74/// Returns the serialized size of `T` and the number of FDs.
75///
76/// This function is not available on Windows.
77#[cfg(unix)]
78pub fn serialized_size_fds<B, T: ?Sized>(
79 ctxt: EncodingContext<B>,
80 value: &T,
81) -> Result<(usize, usize)>
82where
83 B: byteorder::ByteOrder,
84 T: Serialize + DynamicType,
85{
86 let mut null: NullWriteSeek = NullWriteSeek;
87
88 let (len: usize, fds: Vec) = to_writer_fds(&mut null, ctxt, value)?;
89 Ok((len, fds.len()))
90}
91
92/// Serialize `T` to the given `writer`.
93///
94/// This function returns the number of bytes written to the given `writer`.
95///
96/// # Panics
97///
98/// This function will panic if the value to serialize contains file descriptors. Use
99/// [`to_writer_fds`] if you'd want to potentially pass FDs.
100///
101/// # Examples
102///
103/// ```
104/// use zvariant::{EncodingContext, from_slice, to_writer};
105///
106/// let ctxt = EncodingContext::<byteorder::LE>::new_dbus(0);
107/// let mut cursor = std::io::Cursor::new(vec![]);
108/// to_writer(&mut cursor, ctxt, &42u32).unwrap();
109/// let value: u32 = from_slice(cursor.get_ref(), ctxt).unwrap();
110/// assert_eq!(value, 42);
111/// ```
112///
113/// [`to_writer_fds`]: fn.to_writer_fds.html
114pub fn to_writer<B, W, T: ?Sized>(
115 writer: &mut W,
116 ctxt: EncodingContext<B>,
117 value: &T,
118) -> Result<usize>
119where
120 B: byteorder::ByteOrder,
121 W: Write + Seek,
122 T: Serialize + DynamicType,
123{
124 let signature: Signature<'_> = value.dynamic_signature();
125
126 to_writer_for_signature(writer, ctxt, &signature, value)
127}
128
129/// Serialize `T` that (potentially) contains FDs, to the given `writer`.
130///
131/// This function returns the number of bytes written to the given `writer` and the file descriptor
132/// vector, which needs to be transferred via an out-of-band platform specific mechanism.
133///
134/// This function is not available on Windows.
135#[cfg(unix)]
136pub fn to_writer_fds<B, W, T: ?Sized>(
137 writer: &mut W,
138 ctxt: EncodingContext<B>,
139 value: &T,
140) -> Result<(usize, Vec<RawFd>)>
141where
142 B: byteorder::ByteOrder,
143 W: Write + Seek,
144 T: Serialize + DynamicType,
145{
146 let signature: Signature<'_> = value.dynamic_signature();
147
148 to_writer_fds_for_signature(writer, ctxt, &signature, value)
149}
150
151/// Serialize `T` as a byte vector.
152///
153/// See [`from_slice`] documentation for an example of how to use this function.
154///
155/// # Panics
156///
157/// This function will panic if the value to serialize contains file descriptors. Use
158/// [`to_bytes_fds`] if you'd want to potentially pass FDs.
159///
160/// [`to_bytes_fds`]: fn.to_bytes_fds.html
161/// [`from_slice`]: fn.from_slice.html#examples
162pub fn to_bytes<B, T: ?Sized>(ctxt: EncodingContext<B>, value: &T) -> Result<Vec<u8>>
163where
164 B: byteorder::ByteOrder,
165 T: Serialize + DynamicType,
166{
167 let mut cursor: Cursor> = std::io::Cursor::new(inner:vec![]);
168 to_writer(&mut cursor, ctxt, value)?;
169 Ok(cursor.into_inner())
170}
171
172/// Serialize `T` that (potentially) contains FDs, as a byte vector.
173///
174/// The returned file descriptor needs to be transferred via an out-of-band platform specific
175/// mechanism.
176///
177/// This function is not available on Windows.
178#[cfg(unix)]
179pub fn to_bytes_fds<B, T: ?Sized>(
180 ctxt: EncodingContext<B>,
181 value: &T,
182) -> Result<(Vec<u8>, Vec<RawFd>)>
183where
184 B: byteorder::ByteOrder,
185 T: Serialize + DynamicType,
186{
187 let mut cursor: Cursor> = std::io::Cursor::new(inner:vec![]);
188 let (_, fds: Vec) = to_writer_fds(&mut cursor, ctxt, value)?;
189 Ok((cursor.into_inner(), fds))
190}
191
192/// Serialize `T` that has the given signature, to the given `writer`.
193///
194/// Use this function instead of [`to_writer`] if the value being serialized does not implement
195/// [`Type`].
196///
197/// This function returns the number of bytes written to the given `writer`.
198///
199/// [`to_writer`]: fn.to_writer.html
200/// [`Type`]: trait.Type.html
201pub fn to_writer_for_signature<B, W, T: ?Sized>(
202 writer: &mut W,
203 ctxt: EncodingContext<B>,
204 signature: &Signature<'_>,
205 value: &T,
206) -> Result<usize>
207where
208 B: byteorder::ByteOrder,
209 W: Write + Seek,
210 T: Serialize,
211{
212 #[cfg(unix)]
213 {
214 let (len, fds) = to_writer_fds_for_signature(writer, ctxt, signature, value)?;
215 if !fds.is_empty() {
216 panic!("can't serialize with FDs")
217 }
218 Ok(len)
219 }
220
221 #[cfg(not(unix))]
222 {
223 match ctxt.format() {
224 EncodingFormat::DBus => {
225 let mut ser = DBusSerializer::<B, W>::new(signature, writer, ctxt);
226 value.serialize(&mut ser)?;
227 Ok(ser.0.bytes_written)
228 }
229 #[cfg(feature = "gvariant")]
230 EncodingFormat::GVariant => {
231 let mut ser = GVSerializer::<B, W>::new(signature, writer, ctxt);
232 value.serialize(&mut ser)?;
233 Ok(ser.0.bytes_written)
234 }
235 }
236 }
237}
238
239/// Serialize `T` that (potentially) contains FDs and has the given signature, to the given
240/// `writer`.
241///
242/// Use this function instead of [`to_writer_fds`] if the value being serialized does not implement
243/// [`Type`].
244///
245/// This function returns the number of bytes written to the given `writer` and the file descriptor
246/// vector, which needs to be transferred via an out-of-band platform specific mechanism.
247///
248/// This function is not available on Windows.
249///
250/// [`to_writer_fds`]: fn.to_writer_fds.html
251/// [`Type`]: trait.Type.html
252#[cfg(unix)]
253pub fn to_writer_fds_for_signature<B, W, T: ?Sized>(
254 writer: &mut W,
255 ctxt: EncodingContext<B>,
256 signature: &Signature<'_>,
257 value: &T,
258) -> Result<(usize, Vec<RawFd>)>
259where
260 B: byteorder::ByteOrder,
261 W: Write + Seek,
262 T: Serialize,
263{
264 let mut fds: Vec = vec![];
265 match ctxt.format() {
266 EncodingFormat::DBus => {
267 let mut ser: Serializer<'_, '_, B, W> = DBusSerializer::<B, W>::new(signature, writer, &mut fds, ctxt);
268 value.serialize(&mut ser)?;
269 Ok((ser.0.bytes_written, fds))
270 }
271 #[cfg(feature = "gvariant")]
272 EncodingFormat::GVariant => {
273 let mut ser = GVSerializer::<B, W>::new(signature, writer, &mut fds, ctxt);
274 value.serialize(&mut ser)?;
275 Ok((ser.0.bytes_written, fds))
276 }
277 }
278}
279
280/// Serialize `T` that has the given signature, to a new byte vector.
281///
282/// Use this function instead of [`to_bytes`] if the value being serialized does not implement
283/// [`Type`]. See [`from_slice_for_signature`] documentation for an example of how to use this
284/// function.
285///
286/// # Panics
287///
288/// This function will panic if the value to serialize contains file descriptors. Use
289/// [`to_bytes_fds_for_signature`] if you'd want to potentially pass FDs.
290///
291/// [`to_bytes`]: fn.to_bytes.html
292/// [`Type`]: trait.Type.html
293/// [`from_slice_for_signature`]: fn.from_slice_for_signature.html#examples
294pub fn to_bytes_for_signature<B, T: ?Sized>(
295 ctxt: EncodingContext<B>,
296 signature: &Signature<'_>,
297 value: &T,
298) -> Result<Vec<u8>>
299where
300 B: byteorder::ByteOrder,
301 T: Serialize,
302{
303 #[cfg(unix)]
304 {
305 let (bytes: Vec, fds: Vec) = to_bytes_fds_for_signature(ctxt, signature, value)?;
306 if !fds.is_empty() {
307 panic!("can't serialize with FDs")
308 }
309 Ok(bytes)
310 }
311
312 #[cfg(not(unix))]
313 {
314 let mut cursor = std::io::Cursor::new(vec![]);
315 to_writer_for_signature(&mut cursor, ctxt, signature, value)?;
316 Ok(cursor.into_inner())
317 }
318}
319
320/// Serialize `T` that (potentially) contains FDs and has the given signature, to a new byte vector.
321///
322/// Use this function instead of [`to_bytes_fds`] if the value being serialized does not implement
323/// [`Type`].
324///
325/// Please note that the serialized bytes only contain the indices of the file descriptors from the
326/// returned file descriptor vector, which needs to be transferred via an out-of-band platform
327/// specific mechanism.
328///
329/// This function is not available on Windows.
330///
331/// [`to_bytes_fds`]: fn.to_bytes_fds.html
332/// [`Type`]: trait.Type.html
333#[cfg(unix)]
334pub fn to_bytes_fds_for_signature<B, T: ?Sized>(
335 ctxt: EncodingContext<B>,
336 signature: &Signature<'_>,
337 value: &T,
338) -> Result<(Vec<u8>, Vec<RawFd>)>
339where
340 B: byteorder::ByteOrder,
341 T: Serialize,
342{
343 let mut cursor: Cursor> = std::io::Cursor::new(inner:vec![]);
344 let (_, fds: Vec) = to_writer_fds_for_signature(&mut cursor, ctxt, signature, value)?;
345 Ok((cursor.into_inner(), fds))
346}
347
348/// Context for all our serializers and provides shared functionality.
349pub(crate) struct SerializerCommon<'ser, 'sig, B, W> {
350 pub(crate) ctxt: EncodingContext<B>,
351 pub(crate) writer: &'ser mut W,
352 pub(crate) bytes_written: usize,
353 #[cfg(unix)]
354 pub(crate) fds: &'ser mut Vec<RawFd>,
355
356 pub(crate) sig_parser: SignatureParser<'sig>,
357
358 pub(crate) value_sign: Option<Signature<'static>>,
359
360 pub(crate) container_depths: ContainerDepths,
361
362 pub(crate) b: PhantomData<B>,
363}
364
365/// Our serialization implementation.
366///
367/// Using this serializer involves an redirection to the actual serializer. It's best to use the
368/// serialization functions, e.g [`to_bytes`] or specific serializers, [`dbus::Serializer`] or
369/// [`zvariant::Serializer`].
370pub enum Serializer<'ser, 'sig, B, W> {
371 DBus(DBusSerializer<'ser, 'sig, B, W>),
372 #[cfg(feature = "gvariant")]
373 GVariant(GVSerializer<'ser, 'sig, B, W>),
374}
375
376assert_impl_all!(Serializer<'_, '_, i32, i32>: Send, Sync, Unpin);
377
378impl<'ser, 'sig, B, W> Serializer<'ser, 'sig, B, W>
379where
380 B: byteorder::ByteOrder,
381 W: Write + Seek,
382{
383 /// Create a Serializer struct instance.
384 pub fn new<'w: 'ser, 'f: 'ser>(
385 signature: &Signature<'sig>,
386 writer: &'w mut W,
387 #[cfg(unix)] fds: &'f mut Vec<RawFd>,
388 ctxt: EncodingContext<B>,
389 ) -> Self {
390 match ctxt.format() {
391 #[cfg(feature = "gvariant")]
392 EncodingFormat::GVariant => Self::GVariant(GVSerializer::new(
393 signature,
394 writer,
395 #[cfg(unix)]
396 fds,
397 ctxt,
398 )),
399 EncodingFormat::DBus => Self::DBus(DBusSerializer::new(
400 signature,
401 writer,
402 #[cfg(unix)]
403 fds,
404 ctxt,
405 )),
406 }
407 }
408
409 /// Unwrap the `Writer` reference from the `Serializer`.
410 #[inline]
411 pub fn into_inner(self) -> &'ser mut W {
412 match self {
413 #[cfg(feature = "gvariant")]
414 Self::GVariant(ser) => ser.0.writer,
415 Self::DBus(ser) => ser.0.writer,
416 }
417 }
418}
419
420impl<'ser, 'sig, B, W> SerializerCommon<'ser, 'sig, B, W>
421where
422 B: byteorder::ByteOrder,
423 W: Write + Seek,
424{
425 #[cfg(unix)]
426 pub(crate) fn add_fd(&mut self, fd: RawFd) -> u32 {
427 if let Some(idx) = self.fds.iter().position(|&x| x == fd) {
428 return idx as u32;
429 }
430 let idx = self.fds.len();
431 self.fds.push(fd);
432
433 idx as u32
434 }
435
436 pub(crate) fn add_padding(&mut self, alignment: usize) -> Result<usize> {
437 let padding = padding_for_n_bytes(self.abs_pos(), alignment);
438 if padding > 0 {
439 let byte = [0_u8; 1];
440 for _ in 0..padding {
441 self.write_all(&byte)
442 .map_err(|e| Error::InputOutput(e.into()))?;
443 }
444 }
445
446 Ok(padding)
447 }
448
449 pub(crate) fn prep_serialize_basic<T>(&mut self) -> Result<()>
450 where
451 T: Basic,
452 {
453 self.sig_parser.skip_char()?;
454 self.add_padding(T::alignment(self.ctxt.format()))?;
455
456 Ok(())
457 }
458
459 /// This starts the enum serialization.
460 ///
461 /// It's up to the caller to do the rest: serialize the variant payload and skip the `).
462 pub(crate) fn prep_serialize_enum_variant(&mut self, variant_index: u32) -> Result<()> {
463 // Encode enum variants as a struct with first field as variant index
464 let signature = self.sig_parser.next_signature()?;
465 if self.sig_parser.next_char()? != STRUCT_SIG_START_CHAR {
466 return Err(Error::SignatureMismatch(
467 signature.to_owned(),
468 format!("expected `{STRUCT_SIG_START_CHAR}`"),
469 ));
470 }
471
472 let alignment = alignment_for_signature(&signature, self.ctxt.format())?;
473 self.add_padding(alignment)?;
474
475 // Now serialize the veriant index.
476 self.write_u32::<B>(variant_index)
477 .map_err(|e| Error::InputOutput(e.into()))?;
478
479 // Skip the `(`, `u`.
480 self.sig_parser.skip_chars(2)?;
481
482 Ok(())
483 }
484
485 fn abs_pos(&self) -> usize {
486 self.ctxt.position() + self.bytes_written
487 }
488}
489
490impl<'ser, 'sig, B, W> Write for SerializerCommon<'ser, 'sig, B, W>
491where
492 B: byteorder::ByteOrder,
493 W: Write + Seek,
494{
495 /// Write `buf` and increment internal bytes written counter.
496 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
497 self.writer.write(buf).map(|n: usize| {
498 self.bytes_written += n;
499
500 n
501 })
502 }
503
504 fn flush(&mut self) -> std::io::Result<()> {
505 self.writer.flush()
506 }
507}
508
509macro_rules! serialize_method {
510 ($method:ident($($arg:ident: $type:ty),*)) => {
511 serialize_method!(; $method($($arg: $type),*) => () =);
512 };
513 ($($generic:ident),* ; $method:ident($($arg:ident: $type:ty),*)) => {
514 serialize_method!($($generic),*; $method($($arg: $type),*) => () =);
515 };
516 ($($generic:ident),* ; $method:ident($($arg:ident: $type:ty),*) => $ret:ty = $($map:ident)*) => {
517 #[inline]
518 fn $method<$($generic),*>(self, $($arg: $type),*) -> Result<$ret>
519 where
520 $($generic: ?Sized + Serialize),*
521 {
522 match self {
523 #[cfg(feature = "gvariant")]
524 Serializer::GVariant(ser) => {
525 ser.$method($($arg),*)$(.map($map::GVariant))*
526 }
527 Serializer::DBus(ser) => {
528 ser.$method($($arg),*)$(.map($map::DBus))*
529 }
530 }
531 }
532 }
533}
534
535impl<'ser, 'sig, 'b, B, W> ser::Serializer for &'b mut Serializer<'ser, 'sig, B, W>
536where
537 B: byteorder::ByteOrder,
538 W: Write + Seek,
539{
540 type Ok = ();
541 type Error = Error;
542
543 type SerializeSeq = SeqSerializer<'ser, 'sig, 'b, B, W>;
544 type SerializeTuple = StructSerializer<'ser, 'sig, 'b, B, W>;
545 type SerializeTupleStruct = StructSerializer<'ser, 'sig, 'b, B, W>;
546 type SerializeTupleVariant = StructSerializer<'ser, 'sig, 'b, B, W>;
547 type SerializeMap = SeqSerializer<'ser, 'sig, 'b, B, W>;
548 type SerializeStruct = StructSerializer<'ser, 'sig, 'b, B, W>;
549 type SerializeStructVariant = StructSerializer<'ser, 'sig, 'b, B, W>;
550
551 serialize_method!(serialize_bool(b: bool));
552 serialize_method!(serialize_i8(i: i8));
553 serialize_method!(serialize_i16(i: i16));
554 serialize_method!(serialize_i32(i: i32));
555 serialize_method!(serialize_i64(i: i64));
556 serialize_method!(serialize_u8(u: u8));
557 serialize_method!(serialize_u16(u: u16));
558 serialize_method!(serialize_u32(u: u32));
559 serialize_method!(serialize_u64(u: u64));
560 serialize_method!(serialize_f32(f: f32));
561 serialize_method!(serialize_f64(f: f64));
562 serialize_method!(serialize_char(c: char));
563 serialize_method!(serialize_str(s: &str));
564 serialize_method!(serialize_bytes(b: &[u8]));
565 serialize_method!(T; serialize_some(v: &T));
566 serialize_method!(serialize_none());
567 serialize_method!(serialize_unit());
568 serialize_method!(serialize_unit_struct(s: &'static str));
569 serialize_method!(serialize_unit_variant(
570 n: &'static str,
571 i: u32,
572 v: &'static str
573 ));
574 serialize_method!(T; serialize_newtype_struct(n: &'static str, v: &T));
575 serialize_method!(T; serialize_newtype_variant(n: &'static str, i: u32, va: &'static str, v: &T));
576 serialize_method!(; serialize_seq(l: Option<usize>) => Self::SerializeSeq = SeqSerializer);
577 serialize_method!(; serialize_tuple_variant(
578 n: &'static str,
579 i: u32,
580 v: &'static str,
581 l: usize
582 ) => Self::SerializeTupleVariant = StructSerializer);
583 serialize_method!(;serialize_struct_variant(
584 n: &'static str,
585 i: u32,
586 v: &'static str,
587 l: usize
588 ) => Self::SerializeStructVariant = StructSerializer);
589 serialize_method!(; serialize_tuple(l: usize) => Self::SerializeTuple = StructSerializer);
590 serialize_method!(; serialize_tuple_struct(
591 n: &'static str,
592 l: usize
593 ) => Self::SerializeTupleStruct = StructSerializer);
594 serialize_method!(; serialize_map(l: Option<usize>) => Self::SerializeMap = SeqSerializer);
595 serialize_method!(; serialize_struct(
596 n: &'static str,
597 l: usize
598 ) => Self::SerializeStruct = StructSerializer);
599
600 fn is_human_readable(&self) -> bool {
601 false
602 }
603}
604
605macro_rules! serialize_impl {
606 ($trait:ident, $impl:ident, $($method:ident($($arg:ident: $type:ty),*))+) => {
607 impl<'ser, 'sig, 'b, B, W> ser::$trait for $impl<'ser, 'sig, 'b, B, W>
608 where
609 B: byteorder::ByteOrder,
610 W: Write + Seek,
611 {
612 type Ok = ();
613 type Error = Error;
614
615 $(
616 fn $method<T>(&mut self, $($arg: $type),*) -> Result<()>
617 where
618 T: ?Sized + Serialize,
619 {
620 match self {
621 #[cfg(feature = "gvariant")]
622 $impl::GVariant(ser) => ser.$method($($arg),*),
623 $impl::DBus(ser) => ser.$method($($arg),*),
624 }
625 }
626 )*
627
628 fn end(self) -> Result<()> {
629 match self {
630 #[cfg(feature = "gvariant")]
631 $impl::GVariant(ser) => ser.end(),
632 $impl::DBus(ser) => ser.end(),
633 }
634 }
635 }
636 }
637}
638
639#[doc(hidden)]
640pub enum SeqSerializer<'ser, 'sig, 'b, B, W> {
641 DBus(dbus::SeqSerializer<'ser, 'sig, 'b, B, W>),
642 #[cfg(feature = "gvariant")]
643 GVariant(gvariant::SeqSerializer<'ser, 'sig, 'b, B, W>),
644}
645
646serialize_impl!(SerializeSeq, SeqSerializer, serialize_element(value: &T));
647
648#[doc(hidden)]
649pub enum StructSerializer<'ser, 'sig, 'b, B, W> {
650 DBus(dbus::StructSeqSerializer<'ser, 'sig, 'b, B, W>),
651 #[cfg(feature = "gvariant")]
652 GVariant(gvariant::StructSeqSerializer<'ser, 'sig, 'b, B, W>),
653}
654
655serialize_impl!(SerializeTuple, StructSerializer, serialize_element(v: &T));
656serialize_impl!(
657 SerializeTupleStruct,
658 StructSerializer,
659 serialize_field(v: &T)
660);
661serialize_impl!(
662 SerializeTupleVariant,
663 StructSerializer,
664 serialize_field(v: &T)
665);
666serialize_impl!(
667 SerializeStruct,
668 StructSerializer,
669 serialize_field(k: &'static str, v: &T)
670);
671serialize_impl!(
672 SerializeStructVariant,
673 StructSerializer,
674 serialize_field(k: &'static str, v: &T)
675);
676serialize_impl!(SerializeMap, SeqSerializer, serialize_key(v: &T) serialize_value(v: &T));
677