1 | use byteorder::WriteBytesExt; |
2 | use serde::{ser, Serialize}; |
3 | use static_assertions::assert_impl_all; |
4 | use std::{ |
5 | io::{Seek, Write}, |
6 | marker::PhantomData, |
7 | str, |
8 | }; |
9 | |
10 | #[cfg (unix)] |
11 | use std::os::unix::io::RawFd; |
12 | |
13 | #[cfg (feature = "gvariant" )] |
14 | use crate::gvariant::{self, Serializer as GVSerializer}; |
15 | use 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 | |
23 | struct NullWriteSeek; |
24 | |
25 | impl 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 | |
35 | impl 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 |
62 | pub fn serialized_size<B, T: ?Sized>(ctxt: EncodingContext<B>, value: &T) -> Result<usize> |
63 | where |
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)] |
78 | pub fn serialized_size_fds<B, T: ?Sized>( |
79 | ctxt: EncodingContext<B>, |
80 | value: &T, |
81 | ) -> Result<(usize, usize)> |
82 | where |
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 |
114 | pub fn to_writer<B, W, T: ?Sized>( |
115 | writer: &mut W, |
116 | ctxt: EncodingContext<B>, |
117 | value: &T, |
118 | ) -> Result<usize> |
119 | where |
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)] |
136 | pub fn to_writer_fds<B, W, T: ?Sized>( |
137 | writer: &mut W, |
138 | ctxt: EncodingContext<B>, |
139 | value: &T, |
140 | ) -> Result<(usize, Vec<RawFd>)> |
141 | where |
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 |
162 | pub fn to_bytes<B, T: ?Sized>(ctxt: EncodingContext<B>, value: &T) -> Result<Vec<u8>> |
163 | where |
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)] |
179 | pub fn to_bytes_fds<B, T: ?Sized>( |
180 | ctxt: EncodingContext<B>, |
181 | value: &T, |
182 | ) -> Result<(Vec<u8>, Vec<RawFd>)> |
183 | where |
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 |
201 | pub 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> |
207 | where |
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)] |
253 | pub 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>)> |
259 | where |
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 |
294 | pub fn to_bytes_for_signature<B, T: ?Sized>( |
295 | ctxt: EncodingContext<B>, |
296 | signature: &Signature<'_>, |
297 | value: &T, |
298 | ) -> Result<Vec<u8>> |
299 | where |
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)] |
334 | pub 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>)> |
339 | where |
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. |
349 | pub(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`]. |
370 | pub 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 | |
376 | assert_impl_all!(Serializer<'_, '_, i32, i32>: Send, Sync, Unpin); |
377 | |
378 | impl<'ser, 'sig, B, W> Serializer<'ser, 'sig, B, W> |
379 | where |
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 | |
420 | impl<'ser, 'sig, B, W> SerializerCommon<'ser, 'sig, B, W> |
421 | where |
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 | |
490 | impl<'ser, 'sig, B, W> Write for SerializerCommon<'ser, 'sig, B, W> |
491 | where |
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 | |
509 | macro_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 | |
535 | impl<'ser, 'sig, 'b, B, W> ser::Serializer for &'b mut Serializer<'ser, 'sig, B, W> |
536 | where |
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 | |
605 | macro_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)] |
640 | pub 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 | |
646 | serialize_impl!(SerializeSeq, SeqSerializer, serialize_element(value: &T)); |
647 | |
648 | #[doc (hidden)] |
649 | pub 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 | |
655 | serialize_impl!(SerializeTuple, StructSerializer, serialize_element(v: &T)); |
656 | serialize_impl!( |
657 | SerializeTupleStruct, |
658 | StructSerializer, |
659 | serialize_field(v: &T) |
660 | ); |
661 | serialize_impl!( |
662 | SerializeTupleVariant, |
663 | StructSerializer, |
664 | serialize_field(v: &T) |
665 | ); |
666 | serialize_impl!( |
667 | SerializeStruct, |
668 | StructSerializer, |
669 | serialize_field(k: &'static str, v: &T) |
670 | ); |
671 | serialize_impl!( |
672 | SerializeStructVariant, |
673 | StructSerializer, |
674 | serialize_field(k: &'static str, v: &T) |
675 | ); |
676 | serialize_impl!(SerializeMap, SeqSerializer, serialize_key(v: &T) serialize_value(v: &T)); |
677 | |