1 | #![allow (clippy::unusual_byte_groupings)] |
2 | #![deny (rust_2018_idioms)] |
3 | #![doc ( |
4 | html_logo_url = "https://storage.googleapis.com/fdo-gitlab-uploads/project/avatar/3213/zbus-logomark.png" |
5 | )] |
6 | #![doc = include_str!("../README.md" )] |
7 | #![doc (test(attr( |
8 | warn(unused), |
9 | deny(warnings), |
10 | // W/o this, we seem to get some bogus warning about `extern crate zbus`. |
11 | allow(unused_extern_crates), |
12 | )))] |
13 | |
14 | #[macro_use ] |
15 | mod utils; |
16 | pub use utils::*; |
17 | |
18 | mod array; |
19 | pub use array::*; |
20 | |
21 | mod basic; |
22 | pub use basic::*; |
23 | |
24 | mod dict; |
25 | pub use dict::*; |
26 | |
27 | mod encoding_context; |
28 | pub use encoding_context::*; |
29 | |
30 | #[cfg (unix)] |
31 | mod fd; |
32 | #[cfg (unix)] |
33 | pub use fd::*; |
34 | |
35 | mod object_path; |
36 | pub use crate::object_path::*; |
37 | |
38 | mod ser; |
39 | pub use ser::*; |
40 | |
41 | mod de; |
42 | pub use de::*; |
43 | |
44 | pub mod dbus; |
45 | #[cfg (feature = "gvariant" )] |
46 | pub mod gvariant; |
47 | |
48 | mod signature; |
49 | pub use crate::signature::*; |
50 | |
51 | mod str; |
52 | pub use crate::str::*; |
53 | |
54 | mod structure; |
55 | pub use crate::structure::*; |
56 | |
57 | #[cfg (feature = "gvariant" )] |
58 | mod maybe; |
59 | #[cfg (feature = "gvariant" )] |
60 | pub use crate::maybe::*; |
61 | |
62 | mod optional; |
63 | pub use crate::optional::*; |
64 | |
65 | mod value; |
66 | pub use value::*; |
67 | |
68 | mod serialize_value; |
69 | pub use serialize_value::*; |
70 | |
71 | mod deserialize_value; |
72 | pub use deserialize_value::*; |
73 | |
74 | mod error; |
75 | pub use error::*; |
76 | |
77 | #[macro_use ] |
78 | mod r#type; |
79 | pub use r#type::*; |
80 | |
81 | mod from_value; |
82 | |
83 | mod into_value; |
84 | |
85 | mod owned_value; |
86 | pub use owned_value::*; |
87 | |
88 | #[cfg (feature = "gvariant" )] |
89 | mod framing_offset_size; |
90 | #[cfg (feature = "gvariant" )] |
91 | mod framing_offsets; |
92 | mod signature_parser; |
93 | |
94 | mod container_depths; |
95 | |
96 | pub use zvariant_derive::{DeserializeDict, OwnedValue, SerializeDict, Type, TypeDict, Value}; |
97 | |
98 | // Required for the macros to function within this crate. |
99 | extern crate self as zvariant; |
100 | |
101 | // Macro support module, not part of the public API. |
102 | #[doc (hidden)] |
103 | pub mod export { |
104 | pub use serde; |
105 | } |
106 | |
107 | #[cfg (test)] |
108 | #[allow (clippy::disallowed_names)] |
109 | mod tests { |
110 | use std::{ |
111 | collections::HashMap, |
112 | convert::{TryFrom, TryInto}, |
113 | net::{IpAddr, Ipv4Addr, Ipv6Addr}, |
114 | }; |
115 | |
116 | #[cfg (feature = "arrayvec" )] |
117 | use arrayvec::{ArrayString, ArrayVec}; |
118 | use byteorder::{self, ByteOrder, NativeEndian, BE, LE}; |
119 | #[cfg (feature = "arrayvec" )] |
120 | use std::str::FromStr; |
121 | |
122 | #[cfg (feature = "gvariant" )] |
123 | use glib::{Bytes, FromVariant, Variant}; |
124 | use serde::{Deserialize, Serialize}; |
125 | |
126 | use crate::{ |
127 | from_slice, from_slice_for_signature, to_bytes, to_bytes_for_signature, MaxDepthExceeded, |
128 | }; |
129 | #[cfg (unix)] |
130 | use crate::{from_slice_fds, to_bytes_fds}; |
131 | |
132 | #[cfg (unix)] |
133 | use crate::Fd; |
134 | use crate::{ |
135 | Array, Basic, DeserializeDict, DeserializeValue, Dict, EncodingContext as Context, |
136 | EncodingFormat, Error, ObjectPath, Result, SerializeDict, SerializeValue, Signature, Str, |
137 | Structure, Type, Value, |
138 | }; |
139 | |
140 | // Test through both generic and specific API (wrt byte order) |
141 | macro_rules! basic_type_test { |
142 | ($trait:ty, $format:ident, $test_value:expr, $expected_len:expr, $expected_ty:ty, $align:literal) => {{ |
143 | // Lie that we're starting at byte 1 in the overall message to test padding |
144 | let ctxt = Context::<$trait>::new(EncodingFormat::$format, 1); |
145 | #[cfg(unix)] |
146 | let (encoded, fds) = to_bytes_fds(ctxt, &$test_value).unwrap(); |
147 | #[cfg(not(unix))] |
148 | let encoded = to_bytes(ctxt, &$test_value).unwrap(); |
149 | let padding = crate::padding_for_n_bytes(1, $align); |
150 | assert_eq!( |
151 | encoded.len(), |
152 | $expected_len + padding, |
153 | "invalid encoding using `to_bytes`" |
154 | ); |
155 | #[cfg(unix)] |
156 | let decoded: $expected_ty = from_slice_fds(&encoded, Some(&fds), ctxt).unwrap(); |
157 | #[cfg(not(unix))] |
158 | let decoded: $expected_ty = from_slice(&encoded, ctxt).unwrap(); |
159 | assert!( |
160 | decoded == $test_value, |
161 | "invalid decoding using `from_slice`" |
162 | ); |
163 | |
164 | // Now encode w/o padding |
165 | let ctxt = Context::<$trait>::new(EncodingFormat::$format, 0); |
166 | #[cfg(unix)] |
167 | let (encoded, _) = to_bytes_fds(ctxt, &$test_value).unwrap(); |
168 | #[cfg(not(unix))] |
169 | let encoded = to_bytes(ctxt, &$test_value).unwrap(); |
170 | assert_eq!( |
171 | encoded.len(), |
172 | $expected_len, |
173 | "invalid encoding using `to_bytes`" |
174 | ); |
175 | |
176 | encoded |
177 | }}; |
178 | ($trait:ty, $format:ident, $test_value:expr, $expected_len:expr, $expected_ty:ty, $align:literal, $kind:ident, $expected_value_len:expr) => {{ |
179 | let encoded = basic_type_test!( |
180 | $trait, |
181 | $format, |
182 | $test_value, |
183 | $expected_len, |
184 | $expected_ty, |
185 | $align |
186 | ); |
187 | |
188 | // As Value |
189 | let v: Value<'_> = $test_value.into(); |
190 | assert_eq!(v.value_signature(), <$expected_ty>::SIGNATURE_STR); |
191 | assert_eq!(v, Value::$kind($test_value)); |
192 | value_test!(LE, $format, v, $expected_value_len); |
193 | |
194 | let v: $expected_ty = v.try_into().unwrap(); |
195 | assert_eq!(v, $test_value); |
196 | |
197 | encoded |
198 | }}; |
199 | } |
200 | |
201 | macro_rules! value_test { |
202 | ($trait:ty, $format:ident, $test_value:expr, $expected_len:expr) => {{ |
203 | let ctxt = Context::<$trait>::new(EncodingFormat::$format, 0); |
204 | #[cfg(unix)] |
205 | let (encoded, fds) = to_bytes_fds(ctxt, &$test_value).unwrap(); |
206 | #[cfg(not(unix))] |
207 | let encoded = to_bytes(ctxt, &$test_value).unwrap(); |
208 | assert_eq!( |
209 | encoded.len(), |
210 | $expected_len, |
211 | "invalid encoding using `to_bytes`" |
212 | ); |
213 | #[cfg(unix)] |
214 | let decoded: Value<'_> = from_slice_fds(&encoded, Some(&fds), ctxt).unwrap(); |
215 | #[cfg(not(unix))] |
216 | let decoded: Value<'_> = from_slice(&encoded, ctxt).unwrap(); |
217 | assert!( |
218 | decoded == $test_value, |
219 | "invalid decoding using `from_slice`" |
220 | ); |
221 | |
222 | encoded |
223 | }}; |
224 | } |
225 | |
226 | fn f64_type_test( |
227 | format: EncodingFormat, |
228 | value: f64, |
229 | expected_len: usize, |
230 | expected_value_len: usize, |
231 | ) -> Vec<u8> { |
232 | // Lie that we're starting at byte 1 in the overall message to test padding |
233 | let ctxt = Context::<NativeEndian>::new(format, 1); |
234 | let encoded = to_bytes(ctxt, &value).unwrap(); |
235 | let padding = crate::padding_for_n_bytes(1, 8); |
236 | assert_eq!( |
237 | encoded.len(), |
238 | expected_len + padding, |
239 | "invalid encoding using `to_bytes`" |
240 | ); |
241 | |
242 | let decoded: f64 = from_slice(&encoded, ctxt).unwrap(); |
243 | assert!( |
244 | (decoded - value).abs() < f64::EPSILON, |
245 | "invalid decoding using `from_slice`" |
246 | ); |
247 | |
248 | // Now encode w/o padding |
249 | let ctxt = Context::<NativeEndian>::new(format, 0); |
250 | let encoded = to_bytes(ctxt, &value).unwrap(); |
251 | assert_eq!( |
252 | encoded.len(), |
253 | expected_len, |
254 | "invalid encoding using `to_bytes`" |
255 | ); |
256 | |
257 | f64_type_test_as_value(format, value, expected_value_len); |
258 | encoded |
259 | } |
260 | |
261 | fn f64_type_test_as_value(format: EncodingFormat, value: f64, expected_value_len: usize) { |
262 | let v: Value<'_> = value.into(); |
263 | assert_eq!(v.value_signature(), f64::SIGNATURE_STR); |
264 | assert_eq!(v, Value::F64(value)); |
265 | f64_value_test(format, v.clone(), expected_value_len); |
266 | let v: f64 = v.try_into().unwrap(); |
267 | assert!((v - value).abs() < f64::EPSILON); |
268 | } |
269 | |
270 | fn f64_value_test(format: EncodingFormat, v: Value<'_>, expected_value_len: usize) { |
271 | let ctxt = Context::<LE>::new(format, 0); |
272 | let encoded = to_bytes(ctxt, &v).unwrap(); |
273 | assert_eq!( |
274 | encoded.len(), |
275 | expected_value_len, |
276 | "invalid encoding using `to_bytes`" |
277 | ); |
278 | let decoded: Value<'_> = from_slice(&encoded, ctxt).unwrap(); |
279 | assert!(decoded == v, "invalid decoding using `from_slice`" ); |
280 | } |
281 | |
282 | /// Decode with gvariant and compare with expected value (if provided). |
283 | #[cfg (feature = "gvariant" )] |
284 | fn decode_with_gvariant<B, T>(encoded: B, expected_value: Option<T>) -> T |
285 | where |
286 | B: AsRef<[u8]> + Send + 'static, |
287 | T: glib::variant::FromVariant + std::fmt::Debug + PartialEq, |
288 | { |
289 | let bytes = Bytes::from_owned(encoded); |
290 | let gv = Variant::from_bytes::<T>(&bytes); |
291 | let v = gv.get::<T>().unwrap(); |
292 | if let Some(expected_value) = expected_value { |
293 | assert_eq!(v, expected_value); |
294 | } |
295 | |
296 | v |
297 | } |
298 | |
299 | /// Decode a number with gvariant and compare with expected value (if provided). |
300 | /// |
301 | /// `expected_value` is a tuple of (little endian value, big endian value). |
302 | #[cfg (feature = "gvariant" )] |
303 | fn decode_num_with_gvariant<B, T>(encoded: B, expected_value: Option<(T, T)>) -> T |
304 | where |
305 | B: AsRef<[u8]> + Send + 'static, |
306 | T: glib::variant::FromVariant + std::fmt::Debug + PartialEq, |
307 | { |
308 | #[allow (unused_variables)] |
309 | let expected_value = expected_value.map(|(le, be)| { |
310 | #[cfg (target_endian = "little" )] |
311 | { |
312 | le |
313 | } |
314 | |
315 | #[cfg (target_endian = "big" )] |
316 | { |
317 | be |
318 | } |
319 | }); |
320 | decode_with_gvariant(encoded, expected_value) |
321 | } |
322 | |
323 | // All fixed size types have the same encoding in DBus and GVariant formats. |
324 | // |
325 | // NB: Value (i-e VARIANT type) isn't a fixed size type. |
326 | |
327 | #[test ] |
328 | fn u8_value() { |
329 | let encoded = basic_type_test!(LE, DBus, 77_u8, 1, u8, 1, U8, 4); |
330 | assert_eq!(encoded.len(), 1); |
331 | #[cfg (feature = "gvariant" )] |
332 | { |
333 | decode_num_with_gvariant::<_, u8>(encoded, Some((77u8, 77u8))); |
334 | basic_type_test!(LE, GVariant, 77_u8, 1, u8, 1, U8, 3); |
335 | } |
336 | } |
337 | |
338 | #[test ] |
339 | fn i8_value() { |
340 | basic_type_test!(LE, DBus, 77_i8, 2, i8, 2); |
341 | #[cfg (feature = "gvariant" )] |
342 | basic_type_test!(LE, GVariant, 77_i8, 2, i8, 2); |
343 | } |
344 | |
345 | #[cfg (unix)] |
346 | #[test ] |
347 | fn fd_value() { |
348 | basic_type_test!(LE, DBus, Fd::from(42), 4, Fd, 4, Fd, 8); |
349 | #[cfg (feature = "gvariant" )] |
350 | basic_type_test!(LE, GVariant, Fd::from(42), 4, Fd, 4, Fd, 6); |
351 | } |
352 | |
353 | #[test ] |
354 | fn u16_value() { |
355 | let encoded = basic_type_test!(BE, DBus, 0xABBA_u16, 2, u16, 2, U16, 6); |
356 | assert_eq!(encoded.len(), 2); |
357 | #[cfg (feature = "gvariant" )] |
358 | { |
359 | decode_num_with_gvariant::<_, u16>(encoded, Some((0xBAAB_u16, 0xABBA_u16))); |
360 | basic_type_test!(BE, GVariant, 0xABBA_u16, 2, u16, 2, U16, 4); |
361 | } |
362 | } |
363 | |
364 | #[test ] |
365 | fn i16_value() { |
366 | let encoded = basic_type_test!(BE, DBus, -0xAB0_i16, 2, i16, 2, I16, 6); |
367 | assert_eq!(LE::read_i16(&encoded), 0x50F5_i16); |
368 | #[cfg (feature = "gvariant" )] |
369 | { |
370 | decode_num_with_gvariant::<_, i16>(encoded, Some((0x50F5_i16, -0xAB0_i16))); |
371 | basic_type_test!(BE, GVariant, -0xAB0_i16, 2, i16, 2, I16, 4); |
372 | } |
373 | } |
374 | |
375 | #[test ] |
376 | fn u32_value() { |
377 | let encoded = basic_type_test!(BE, DBus, 0xABBA_ABBA_u32, 4, u32, 4, U32, 8); |
378 | assert_eq!(encoded.len(), 4); |
379 | #[cfg (feature = "gvariant" )] |
380 | { |
381 | decode_num_with_gvariant::<_, u32>(encoded, Some((0xBAAB_BAAB_u32, 0xABBA_ABBA_u32))); |
382 | basic_type_test!(BE, GVariant, 0xABBA_ABBA_u32, 4, u32, 4, U32, 6); |
383 | } |
384 | } |
385 | |
386 | #[test ] |
387 | fn i32_value() { |
388 | let encoded = basic_type_test!(BE, DBus, -0xABBA_AB0_i32, 4, i32, 4, I32, 8); |
389 | assert_eq!(LE::read_i32(&encoded), 0x5055_44F5_i32); |
390 | #[cfg (feature = "gvariant" )] |
391 | { |
392 | decode_num_with_gvariant::<_, i32>(encoded, Some((0x5055_44F5_i32, -0xABBA_AB0_i32))); |
393 | basic_type_test!(BE, GVariant, -0xABBA_AB0_i32, 4, i32, 4, I32, 6); |
394 | } |
395 | } |
396 | |
397 | // u64 is covered by `value_value` test below |
398 | |
399 | #[test ] |
400 | fn i64_value() { |
401 | let encoded = basic_type_test!(BE, DBus, -0xABBA_ABBA_ABBA_AB0_i64, 8, i64, 8, I64, 16); |
402 | assert_eq!(LE::read_i64(&encoded), 0x5055_4455_4455_44F5_i64); |
403 | #[cfg (feature = "gvariant" )] |
404 | { |
405 | decode_num_with_gvariant::<_, i64>( |
406 | encoded, |
407 | Some((0x5055_4455_4455_44F5_i64, -0xABBA_ABBA_ABBA_AB0_i64)), |
408 | ); |
409 | basic_type_test!(BE, GVariant, -0xABBA_ABBA_ABBA_AB0_i64, 8, i64, 8, I64, 10); |
410 | } |
411 | } |
412 | |
413 | #[test ] |
414 | fn f64_value() { |
415 | let encoded = f64_type_test(EncodingFormat::DBus, 99999.99999_f64, 8, 16); |
416 | assert!((NativeEndian::read_f64(&encoded) - 99999.99999_f64).abs() < f64::EPSILON); |
417 | #[cfg (feature = "gvariant" )] |
418 | { |
419 | assert!( |
420 | (decode_with_gvariant::<_, f64>(encoded, None) - 99999.99999_f64).abs() |
421 | < f64::EPSILON |
422 | ); |
423 | f64_type_test(EncodingFormat::GVariant, 99999.99999_f64, 8, 10); |
424 | } |
425 | } |
426 | |
427 | #[test ] |
428 | fn str_value() { |
429 | let string = String::from("hello world" ); |
430 | basic_type_test!(LE, DBus, string, 16, String, 4); |
431 | basic_type_test!(LE, DBus, string, 16, &str, 4); |
432 | |
433 | // GVariant format now |
434 | #[cfg (feature = "gvariant" )] |
435 | { |
436 | let encoded = basic_type_test!(LE, GVariant, string, 12, String, 1); |
437 | decode_with_gvariant::<_, String>(encoded, Some(String::from("hello world" ))); |
438 | } |
439 | |
440 | let string = "hello world" ; |
441 | basic_type_test!(LE, DBus, string, 16, &str, 4); |
442 | basic_type_test!(LE, DBus, string, 16, String, 4); |
443 | |
444 | // As Value |
445 | let v: Value<'_> = string.into(); |
446 | assert_eq!(v.value_signature(), "s" ); |
447 | assert_eq!(v, Value::new("hello world" )); |
448 | value_test!(LE, DBus, v, 20); |
449 | #[cfg (feature = "gvariant" )] |
450 | { |
451 | let encoded = value_test!(LE, GVariant, v, 14); |
452 | |
453 | // Check encoding against GLib |
454 | let bytes = Bytes::from_owned(encoded); |
455 | let gv = Variant::from_bytes::<Variant>(&bytes); |
456 | let variant = gv.as_variant().unwrap(); |
457 | assert_eq!(variant.str().unwrap(), "hello world" ); |
458 | } |
459 | |
460 | let v: String = v.try_into().unwrap(); |
461 | assert_eq!(v, "hello world" ); |
462 | |
463 | // Check for interior null bytes which are not allowed |
464 | let ctxt = Context::<LE>::new_dbus(0); |
465 | assert!(from_slice::<_, &str>(b" \x0b\0\0\0hello \0world \0" , ctxt).is_err()); |
466 | assert!(to_bytes(ctxt, &"hello \0world" ).is_err()); |
467 | |
468 | // GVariant format doesn't allow null bytes either |
469 | #[cfg (feature = "gvariant" )] |
470 | { |
471 | let ctxt = Context::<LE>::new_gvariant(0); |
472 | assert!(from_slice::<_, &str>(b"hello \0world \0" , ctxt).is_err()); |
473 | assert!(to_bytes(ctxt, &"hello \0world" ).is_err()); |
474 | } |
475 | |
476 | // Characters are treated as strings |
477 | basic_type_test!(LE, DBus, 'c' , 6, char, 4); |
478 | #[cfg (feature = "gvariant" )] |
479 | basic_type_test!(LE, GVariant, 'c' , 2, char, 1); |
480 | |
481 | // As Value |
482 | let v: Value<'_> = "c" .into(); |
483 | assert_eq!(v.value_signature(), "s" ); |
484 | let ctxt = Context::new_dbus(0); |
485 | let encoded = to_bytes::<LE, _>(ctxt, &v).unwrap(); |
486 | assert_eq!(encoded.len(), 10); |
487 | let v = from_slice::<LE, Value<'_>>(&encoded, ctxt).unwrap(); |
488 | assert_eq!(v, Value::new("c" )); |
489 | } |
490 | |
491 | #[cfg (feature = "arrayvec" )] |
492 | #[test ] |
493 | fn array_string_value() { |
494 | let s = ArrayString::<32>::from_str("hello world!" ).unwrap(); |
495 | let ctxt = Context::<LE>::new_dbus(0); |
496 | let encoded = to_bytes(ctxt, &s).unwrap(); |
497 | assert_eq!(encoded.len(), 17); |
498 | let decoded: ArrayString<32> = from_slice(&encoded, ctxt).unwrap(); |
499 | assert_eq!(&decoded, "hello world!" ); |
500 | } |
501 | |
502 | #[test ] |
503 | fn signature_value() { |
504 | let sig = Signature::try_from("yys" ).unwrap(); |
505 | basic_type_test!(LE, DBus, sig, 5, Signature<'_>, 1); |
506 | |
507 | #[cfg (feature = "gvariant" )] |
508 | { |
509 | let encoded = basic_type_test!(LE, GVariant, sig, 4, Signature<'_>, 1); |
510 | decode_with_gvariant::<_, String>(encoded, Some(String::from("yys" ))); |
511 | } |
512 | |
513 | // As Value |
514 | let v: Value<'_> = sig.into(); |
515 | assert_eq!(v.value_signature(), "g" ); |
516 | let encoded = value_test!(LE, DBus, v, 8); |
517 | let ctxt = Context::new_dbus(0); |
518 | let v = from_slice::<LE, Value<'_>>(&encoded, ctxt).unwrap(); |
519 | assert_eq!(v, Value::Signature(Signature::try_from("yys" ).unwrap())); |
520 | |
521 | // GVariant format now |
522 | #[cfg (feature = "gvariant" )] |
523 | { |
524 | let encoded = value_test!(LE, GVariant, v, 6); |
525 | let ctxt = Context::new_gvariant(0); |
526 | let v = from_slice::<LE, Value<'_>>(&encoded, ctxt).unwrap(); |
527 | assert_eq!(v, Value::Signature(Signature::try_from("yys" ).unwrap())); |
528 | } |
529 | } |
530 | |
531 | #[test ] |
532 | fn object_path_value() { |
533 | let o = ObjectPath::try_from("/hello/world" ).unwrap(); |
534 | basic_type_test!(LE, DBus, o, 17, ObjectPath<'_>, 4); |
535 | |
536 | #[cfg (feature = "gvariant" )] |
537 | { |
538 | let encoded = basic_type_test!(LE, GVariant, o, 13, ObjectPath<'_>, 1); |
539 | decode_with_gvariant::<_, String>(encoded, Some(String::from("/hello/world" ))); |
540 | } |
541 | |
542 | // As Value |
543 | let v: Value<'_> = o.into(); |
544 | assert_eq!(v.value_signature(), "o" ); |
545 | let encoded = value_test!(LE, DBus, v, 21); |
546 | let ctxt = Context::new_dbus(0); |
547 | let v = from_slice::<LE, Value<'_>>(&encoded, ctxt).unwrap(); |
548 | assert_eq!( |
549 | v, |
550 | Value::ObjectPath(ObjectPath::try_from("/hello/world" ).unwrap()) |
551 | ); |
552 | |
553 | // GVariant format now |
554 | #[cfg (feature = "gvariant" )] |
555 | { |
556 | let encoded = value_test!(LE, GVariant, v, 15); |
557 | let ctxt = Context::new_gvariant(0); |
558 | let v = from_slice::<LE, Value<'_>>(&encoded, ctxt).unwrap(); |
559 | assert_eq!( |
560 | v, |
561 | Value::ObjectPath(ObjectPath::try_from("/hello/world" ).unwrap()) |
562 | ); |
563 | } |
564 | } |
565 | |
566 | #[cfg (unix)] |
567 | #[test ] |
568 | fn unit_fds() { |
569 | let ctxt = Context::<BE>::new_dbus(0); |
570 | let (encoded, fds) = to_bytes_fds(ctxt, &()).unwrap(); |
571 | assert_eq!(encoded.len(), 0, "invalid encoding using `to_bytes`" ); |
572 | let _: () = from_slice_fds(&encoded, Some(&fds), ctxt) |
573 | .expect("invalid decoding using `from_slice`" ); |
574 | } |
575 | |
576 | #[test ] |
577 | fn unit() { |
578 | let ctxt = Context::<BE>::new_dbus(0); |
579 | let encoded = to_bytes(ctxt, &()).unwrap(); |
580 | assert_eq!(encoded.len(), 0, "invalid encoding using `to_bytes`" ); |
581 | let _: () = from_slice(&encoded, ctxt).expect("invalid decoding using `from_slice`" ); |
582 | } |
583 | |
584 | #[test ] |
585 | fn array_value() { |
586 | // Let's use D-Bus/GVariant terms |
587 | |
588 | // |
589 | // Array of u8 |
590 | // |
591 | // First a normal Rust array that is actually serialized as a struct (thank you Serde!) |
592 | assert_eq!(<[u8; 2]>::signature(), "(yy)" ); |
593 | let ay = [77u8, 88]; |
594 | let ctxt = Context::<LE>::new_dbus(0); |
595 | let encoded = to_bytes(ctxt, &ay).unwrap(); |
596 | assert_eq!(encoded.len(), 2); |
597 | let decoded: [u8; 2] = from_slice(&encoded, ctxt).unwrap(); |
598 | assert_eq!(&decoded, &[77u8, 88]); |
599 | |
600 | // Then rest of the tests just use ArrayVec or Vec |
601 | #[cfg (feature = "arrayvec" )] |
602 | let ay = ArrayVec::from([77u8, 88]); |
603 | #[cfg (not(feature = "arrayvec" ))] |
604 | let ay = vec![77u8, 88]; |
605 | let ctxt = Context::<LE>::new_dbus(0); |
606 | let encoded = to_bytes(ctxt, &ay).unwrap(); |
607 | assert_eq!(encoded.len(), 6); |
608 | |
609 | #[cfg (feature = "arrayvec" )] |
610 | let decoded: ArrayVec<u8, 2> = from_slice(&encoded, ctxt).unwrap(); |
611 | #[cfg (not(feature = "arrayvec" ))] |
612 | let decoded: Vec<u8> = from_slice(&encoded, ctxt).unwrap(); |
613 | assert_eq!(&decoded.as_slice(), &[77u8, 88]); |
614 | |
615 | // GVariant format now |
616 | #[cfg (feature = "gvariant" )] |
617 | { |
618 | let ctxt = Context::<LE>::new_gvariant(0); |
619 | let gv_encoded = to_bytes(ctxt, &ay).unwrap(); |
620 | assert_eq!(gv_encoded.len(), 2); |
621 | |
622 | // Check encoding against GLib |
623 | let bytes = Bytes::from_owned(gv_encoded); |
624 | let variant = Variant::from_bytes::<&[u8]>(&bytes); |
625 | assert_eq!(variant.n_children(), 2); |
626 | assert_eq!(variant.child_value(0).get::<u8>().unwrap(), 77); |
627 | assert_eq!(variant.child_value(1).get::<u8>().unwrap(), 88); |
628 | } |
629 | let ctxt = Context::<LE>::new_dbus(0); |
630 | |
631 | // As Value |
632 | let v: Value<'_> = ay[..].into(); |
633 | assert_eq!(v.value_signature(), "ay" ); |
634 | let encoded = to_bytes::<LE, _>(ctxt, &v).unwrap(); |
635 | assert_eq!(encoded.len(), 10); |
636 | let v = from_slice::<LE, Value<'_>>(&encoded, ctxt).unwrap(); |
637 | if let Value::Array(array) = v { |
638 | assert_eq!(*array.element_signature(), "y" ); |
639 | assert_eq!(array.len(), 2); |
640 | assert_eq!(array.get()[0], Value::U8(77)); |
641 | assert_eq!(array.get()[1], Value::U8(88)); |
642 | } else { |
643 | panic!(); |
644 | } |
645 | |
646 | // Now try as Vec |
647 | let vec = ay.to_vec(); |
648 | let encoded = to_bytes::<LE, _>(ctxt, &vec).unwrap(); |
649 | assert_eq!(encoded.len(), 6); |
650 | |
651 | // Vec as Value |
652 | let v: Value<'_> = Array::from(&vec).into(); |
653 | assert_eq!(v.value_signature(), "ay" ); |
654 | let encoded = to_bytes::<LE, _>(ctxt, &v).unwrap(); |
655 | assert_eq!(encoded.len(), 10); |
656 | |
657 | // Empty array |
658 | let at: Vec<u64> = vec![]; |
659 | let encoded = to_bytes::<LE, _>(ctxt, &at).unwrap(); |
660 | assert_eq!(encoded.len(), 8); |
661 | |
662 | // GVariant format now |
663 | #[cfg (feature = "gvariant" )] |
664 | { |
665 | let ctxt = Context::<LE>::new_gvariant(0); |
666 | let gv_encoded = to_bytes(ctxt, &at).unwrap(); |
667 | assert_eq!(gv_encoded.len(), 0); |
668 | let at = from_slice::<LE, Vec<u64>>(&gv_encoded, ctxt).unwrap(); |
669 | assert_eq!(at.len(), 0); |
670 | } |
671 | let ctxt = Context::<LE>::new_dbus(0); |
672 | |
673 | // As Value |
674 | let v: Value<'_> = at[..].into(); |
675 | assert_eq!(v.value_signature(), "at" ); |
676 | let encoded = to_bytes::<LE, _>(ctxt, &v).unwrap(); |
677 | assert_eq!(encoded.len(), 8); |
678 | let v = from_slice::<LE, Value<'_>>(&encoded, ctxt).unwrap(); |
679 | if let Value::Array(array) = v { |
680 | assert_eq!(*array.element_signature(), "t" ); |
681 | assert_eq!(array.len(), 0); |
682 | } else { |
683 | panic!(); |
684 | } |
685 | |
686 | // GVariant format now |
687 | #[cfg (feature = "gvariant" )] |
688 | { |
689 | let ctxt = Context::<LE>::new_gvariant(0); |
690 | let v: Value<'_> = at[..].into(); |
691 | let gv_encoded = to_bytes(ctxt, &v).unwrap(); |
692 | assert_eq!(gv_encoded.len(), 3); |
693 | let v = from_slice::<LE, Value<'_>>(&gv_encoded, ctxt).unwrap(); |
694 | if let Value::Array(array) = v { |
695 | assert_eq!(*array.element_signature(), "t" ); |
696 | assert_eq!(array.len(), 0); |
697 | } else { |
698 | panic!(); |
699 | } |
700 | |
701 | // Check encoding against GLib |
702 | let bytes = Bytes::from_owned(gv_encoded); |
703 | let variant = Variant::from_bytes::<&[&str]>(&bytes); |
704 | assert_eq!(variant.n_children(), 0); |
705 | } |
706 | let ctxt = Context::<LE>::new_dbus(0); |
707 | |
708 | // |
709 | // Array of strings |
710 | // |
711 | // Can't use 'as' as it's a keyword |
712 | let as_ = vec!["Hello" , "World" , "Now" , "Bye!" ]; |
713 | let encoded = to_bytes::<LE, _>(ctxt, &as_).unwrap(); |
714 | assert_eq!(encoded.len(), 45); |
715 | let decoded = from_slice::<LE, Vec<&str>>(&encoded, ctxt).unwrap(); |
716 | assert_eq!(decoded.len(), 4); |
717 | assert_eq!(decoded[0], "Hello" ); |
718 | assert_eq!(decoded[1], "World" ); |
719 | |
720 | let decoded = from_slice::<LE, Vec<String>>(&encoded, ctxt).unwrap(); |
721 | assert_eq!(decoded.as_slice(), as_.as_slice()); |
722 | |
723 | // Decode just the second string |
724 | let ctxt = Context::<LE>::new_dbus(14); |
725 | let decoded: &str = from_slice(&encoded[14..], ctxt).unwrap(); |
726 | assert_eq!(decoded, "World" ); |
727 | let ctxt = Context::<LE>::new_dbus(0); |
728 | |
729 | // As Value |
730 | let v: Value<'_> = as_[..].into(); |
731 | assert_eq!(v.value_signature(), "as" ); |
732 | let encoded = to_bytes(ctxt, &v).unwrap(); |
733 | assert_eq!(encoded.len(), 49); |
734 | let v = from_slice(&encoded, ctxt).unwrap(); |
735 | if let Value::Array(array) = v { |
736 | assert_eq!(*array.element_signature(), "s" ); |
737 | assert_eq!(array.len(), 4); |
738 | assert_eq!(array.get()[0], Value::new("Hello" )); |
739 | assert_eq!(array.get()[1], Value::new("World" )); |
740 | } else { |
741 | panic!(); |
742 | } |
743 | |
744 | let v: Value<'_> = as_[..].into(); |
745 | let a: Array<'_> = v.try_into().unwrap(); |
746 | let _ve: Vec<String> = a.try_into().unwrap(); |
747 | |
748 | // GVariant format now |
749 | #[cfg (feature = "gvariant" )] |
750 | { |
751 | let ctxt = Context::<LE>::new_gvariant(0); |
752 | let v: Value<'_> = as_[..].into(); |
753 | let gv_encoded = to_bytes(ctxt, &v).unwrap(); |
754 | assert_eq!(gv_encoded.len(), 28); |
755 | |
756 | // Check encoding against GLib |
757 | let bytes = Bytes::from_owned(gv_encoded); |
758 | let variant = Variant::from_bytes::<Variant>(&bytes); |
759 | assert_eq!(variant.n_children(), 1); |
760 | let decoded: Vec<String> = variant.child_value(0).get().unwrap(); |
761 | assert_eq!(decoded[0], "Hello" ); |
762 | assert_eq!(decoded[1], "World" ); |
763 | } |
764 | |
765 | // Array of Struct, which in turn containin an Array (We gotta go deeper!) |
766 | // Signature: "a(yu(xbxas)s)"); |
767 | let ar = vec![( |
768 | // top-most simple fields |
769 | u8::max_value(), |
770 | u32::max_value(), |
771 | ( |
772 | // 2nd level simple fields |
773 | i64::max_value(), |
774 | true, |
775 | i64::max_value(), |
776 | // 2nd level array field |
777 | &["Hello" , "World" ][..], |
778 | ), |
779 | // one more top-most simple field |
780 | "hello" , |
781 | )]; |
782 | let ctxt = Context::<LE>::new_dbus(0); |
783 | let encoded = to_bytes(ctxt, &ar).unwrap(); |
784 | assert_eq!(encoded.len(), 78); |
785 | let decoded = |
786 | from_slice::<LE, Vec<(u8, u32, (i64, bool, i64, Vec<&str>), &str)>>(&encoded, ctxt) |
787 | .unwrap(); |
788 | assert_eq!(decoded.len(), 1); |
789 | let r = &decoded[0]; |
790 | assert_eq!(r.0, u8::max_value()); |
791 | assert_eq!(r.1, u32::max_value()); |
792 | let inner_r = &r.2; |
793 | assert_eq!(inner_r.0, i64::max_value()); |
794 | assert!(inner_r.1); |
795 | assert_eq!(inner_r.2, i64::max_value()); |
796 | let as_ = &inner_r.3; |
797 | assert_eq!(as_.len(), 2); |
798 | assert_eq!(as_[0], "Hello" ); |
799 | assert_eq!(as_[1], "World" ); |
800 | assert_eq!(r.3, "hello" ); |
801 | |
802 | // GVariant format now |
803 | #[cfg (feature = "gvariant" )] |
804 | { |
805 | let ctxt = Context::<LE>::new_gvariant(0); |
806 | let gv_encoded = to_bytes(ctxt, &ar).unwrap(); |
807 | assert_eq!(gv_encoded.len(), 54); |
808 | let decoded = from_slice::<LE, Vec<(u8, u32, (i64, bool, i64, Vec<&str>), &str)>>( |
809 | &gv_encoded, |
810 | ctxt, |
811 | ) |
812 | .unwrap(); |
813 | assert_eq!(decoded.len(), 1); |
814 | let r = &decoded[0]; |
815 | assert_eq!(r.0, u8::max_value()); |
816 | assert_eq!(r.1, u32::max_value()); |
817 | let inner_r = &r.2; |
818 | assert_eq!(inner_r.0, i64::max_value()); |
819 | assert!(inner_r.1); |
820 | assert_eq!(inner_r.2, i64::max_value()); |
821 | let as_ = &inner_r.3; |
822 | assert_eq!(as_.len(), 2); |
823 | assert_eq!(as_[0], "Hello" ); |
824 | assert_eq!(as_[1], "World" ); |
825 | assert_eq!(r.3, "hello" ); |
826 | |
827 | // Check encoding against GLib |
828 | let bytes = Bytes::from_owned(gv_encoded); |
829 | let variant = Variant::from_bytes::< |
830 | Vec<(u8, u32, (i64, bool, i64, Vec<String>), String)>, |
831 | >(&bytes); |
832 | assert_eq!(variant.n_children(), 1); |
833 | let r: (u8, u32, (i64, bool, i64, Vec<String>), String) = |
834 | variant.child_value(0).get().unwrap(); |
835 | assert_eq!(r.0, u8::max_value()); |
836 | assert_eq!(r.1, u32::max_value()); |
837 | } |
838 | let ctxt = Context::<LE>::new_dbus(0); |
839 | |
840 | // As Value |
841 | let v: Value<'_> = ar[..].into(); |
842 | assert_eq!(v.value_signature(), "a(yu(xbxas)s)" ); |
843 | let encoded = to_bytes::<LE, _>(ctxt, &v).unwrap(); |
844 | assert_eq!(encoded.len(), 94); |
845 | let v = from_slice::<LE, Value<'_>>(&encoded, ctxt).unwrap(); |
846 | if let Value::Array(array) = v.clone() { |
847 | assert_eq!(*array.element_signature(), "(yu(xbxas)s)" ); |
848 | assert_eq!(array.len(), 1); |
849 | let r = &array.get()[0]; |
850 | if let Value::Structure(r) = r { |
851 | let fields = r.fields(); |
852 | assert_eq!(fields[0], Value::U8(u8::max_value())); |
853 | assert_eq!(fields[1], Value::U32(u32::max_value())); |
854 | if let Value::Structure(r) = &fields[2] { |
855 | let fields = r.fields(); |
856 | assert_eq!(fields[0], Value::I64(i64::max_value())); |
857 | assert_eq!(fields[1], Value::Bool(true)); |
858 | assert_eq!(fields[2], Value::I64(i64::max_value())); |
859 | if let Value::Array(as_) = &fields[3] { |
860 | assert_eq!(as_.len(), 2); |
861 | assert_eq!(as_.get()[0], Value::new("Hello" )); |
862 | assert_eq!(as_.get()[1], Value::new("World" )); |
863 | } else { |
864 | panic!(); |
865 | } |
866 | } else { |
867 | panic!(); |
868 | } |
869 | assert_eq!(fields[3], Value::new("hello" )); |
870 | } else { |
871 | panic!(); |
872 | } |
873 | } else { |
874 | panic!(); |
875 | } |
876 | |
877 | // GVariant format now |
878 | #[cfg (feature = "gvariant" )] |
879 | { |
880 | use rand::{distributions::Alphanumeric, thread_rng, Rng}; |
881 | |
882 | let ctxt = Context::<LE>::new_gvariant(0); |
883 | let gv_encoded = to_bytes(ctxt, &v).unwrap(); |
884 | assert_eq!(gv_encoded.len(), 68); |
885 | let v = from_slice::<LE, Value<'_>>(&gv_encoded, ctxt).unwrap(); |
886 | if let Value::Array(array) = v { |
887 | assert_eq!(*array.element_signature(), "(yu(xbxas)s)" ); |
888 | assert_eq!(array.len(), 1); |
889 | let r = &array.get()[0]; |
890 | if let Value::Structure(r) = r { |
891 | let fields = r.fields(); |
892 | assert_eq!(fields[0], Value::U8(u8::max_value())); |
893 | assert_eq!(fields[1], Value::U32(u32::max_value())); |
894 | if let Value::Structure(r) = &fields[2] { |
895 | let fields = r.fields(); |
896 | assert_eq!(fields[0], Value::I64(i64::max_value())); |
897 | assert_eq!(fields[1], Value::Bool(true)); |
898 | assert_eq!(fields[2], Value::I64(i64::max_value())); |
899 | if let Value::Array(as_) = &fields[3] { |
900 | assert_eq!(as_.len(), 2); |
901 | assert_eq!(as_.get()[0], Value::new("Hello" )); |
902 | assert_eq!(as_.get()[1], Value::new("World" )); |
903 | } else { |
904 | panic!(); |
905 | } |
906 | } else { |
907 | panic!(); |
908 | } |
909 | assert_eq!(fields[3], Value::new("hello" )); |
910 | } else { |
911 | panic!(); |
912 | } |
913 | } else { |
914 | panic!(); |
915 | } |
916 | |
917 | // Check encoding against GLib |
918 | let bytes = Bytes::from_owned(gv_encoded); |
919 | let variant = Variant::from_bytes::<Variant>(&bytes); |
920 | assert_eq!(variant.n_children(), 1); |
921 | let child: Variant = variant.child_value(0); |
922 | let r: (u8, u32, (i64, bool, i64, Vec<String>), String) = |
923 | child.child_value(0).get().unwrap(); |
924 | assert_eq!(r.0, u8::max_value()); |
925 | assert_eq!(r.1, u32::max_value()); |
926 | |
927 | let mut rng = thread_rng(); |
928 | // Let's test GVariant ser/de of a 254 byte array with variable-width elements as to |
929 | // ensure no problems with non-normal BS of GVariant. |
930 | let as_ = vec![ |
931 | (&mut rng) |
932 | .sample_iter(Alphanumeric) |
933 | .map(char::from) |
934 | .take(126) |
935 | .collect::<String>(), |
936 | (&mut rng) |
937 | .sample_iter(Alphanumeric) |
938 | .map(char::from) |
939 | .take(126) |
940 | .collect::<String>(), |
941 | ]; |
942 | let gv_encoded = to_bytes(ctxt, &as_).unwrap(); |
943 | // 252 chars + 2 null terminator bytes doesn't leave room for 2 framing offset bytes so |
944 | // a 2-byte offset is chosen by the serializer. |
945 | assert_eq!(gv_encoded.len(), 258); |
946 | |
947 | // Check encoding against GLib |
948 | let bytes = Bytes::from_owned(gv_encoded.clone()); |
949 | let variant = Variant::from_bytes::<Vec<String>>(&bytes); |
950 | assert_eq!(variant.n_children(), 2); |
951 | assert_eq!(variant.child_value(0).get::<String>().unwrap(), as_[0]); |
952 | assert_eq!(variant.child_value(1).get::<String>().unwrap(), as_[1]); |
953 | // Also check if our own deserializer does the right thing |
954 | let as2 = from_slice::<LE, Vec<String>>(&gv_encoded, ctxt).unwrap(); |
955 | assert_eq!(as2, as_); |
956 | |
957 | // Test conversion of Array of Value to Vec<Value> |
958 | let v = Value::new(vec![Value::new(43), Value::new("bonjour" )]); |
959 | let av = <Array<'_>>::try_from(v).unwrap(); |
960 | let av = <Vec<Value<'_>>>::try_from(av).unwrap(); |
961 | assert_eq!(av[0], Value::new(43)); |
962 | assert_eq!(av[1], Value::new("bonjour" )); |
963 | |
964 | let vec = vec![1, 2]; |
965 | let val = Value::new(&vec); |
966 | assert_eq!(TryInto::<Vec<i32>>::try_into(val).unwrap(), vec); |
967 | } |
968 | } |
969 | |
970 | #[test ] |
971 | fn struct_byte_array() { |
972 | let ctxt = Context::<LE>::new_dbus(0); |
973 | let value: (Vec<u8>, HashMap<String, Value<'_>>) = (Vec::new(), HashMap::new()); |
974 | let value = zvariant::to_bytes(ctxt, &value).unwrap(); |
975 | #[cfg (feature = "serde_bytes" )] |
976 | let (bytes, map): (&serde_bytes::Bytes, HashMap<&str, Value<'_>>) = |
977 | zvariant::from_slice(&value, ctxt) |
978 | .expect("Could not deserialize serde_bytes::Bytes in struct." ); |
979 | #[cfg (not(feature = "serde_bytes" ))] |
980 | let (bytes, map): (&[u8], HashMap<&str, Value<'_>>) = |
981 | zvariant::from_slice(&value, ctxt).expect("Could not deserialize u8 slice in struct" ); |
982 | |
983 | assert!(bytes.is_empty()); |
984 | assert!(map.is_empty()); |
985 | } |
986 | |
987 | #[test ] |
988 | fn struct_value() { |
989 | // Struct->Value |
990 | let s: Value<'_> = ("a" , "b" , (1, 2)).into(); |
991 | |
992 | let ctxt = Context::<LE>::new_dbus(0); |
993 | let encoded = to_bytes(ctxt, &s).unwrap(); |
994 | assert_eq!(dbg!(encoded.len()), 40); |
995 | let decoded: Value<'_> = from_slice(&encoded, ctxt).unwrap(); |
996 | let s = <Structure<'_>>::try_from(decoded).unwrap(); |
997 | let outer = <(Str<'_>, Str<'_>, Structure<'_>)>::try_from(s).unwrap(); |
998 | assert_eq!(outer.0, "a" ); |
999 | assert_eq!(outer.1, "b" ); |
1000 | |
1001 | let inner = <(i32, i32)>::try_from(outer.2).unwrap(); |
1002 | assert_eq!(inner.0, 1); |
1003 | assert_eq!(inner.1, 2); |
1004 | |
1005 | #[derive (Serialize, Deserialize, Type, PartialEq, Debug)] |
1006 | struct Foo { |
1007 | val: u32, |
1008 | } |
1009 | |
1010 | let foo = Foo { val: 99 }; |
1011 | let v = SerializeValue(&foo); |
1012 | let encoded = to_bytes(ctxt, &v).unwrap(); |
1013 | let decoded: DeserializeValue<'_, Foo> = from_slice(&encoded, ctxt).unwrap(); |
1014 | assert_eq!(decoded.0, foo); |
1015 | |
1016 | // Unit struct should be treated as a 0-sized tuple (the same as unit type) |
1017 | #[derive (Serialize, Deserialize, Type, PartialEq, Debug)] |
1018 | struct Unit; |
1019 | |
1020 | assert_eq!(Unit::signature(), "" ); |
1021 | let encoded = to_bytes(ctxt, &Unit).unwrap(); |
1022 | assert_eq!(encoded.len(), 0); |
1023 | let _decoded: Unit = from_slice(&encoded, ctxt).unwrap(); |
1024 | |
1025 | // Structs w/o fields should be treated as a unit struct. |
1026 | #[derive (Serialize, Deserialize, Type, PartialEq, Debug)] |
1027 | struct NoFields {} |
1028 | |
1029 | assert_eq!(NoFields::signature(), "y" ); |
1030 | let encoded = to_bytes(ctxt, &NoFields {}).unwrap(); |
1031 | assert_eq!(encoded.len(), 1); |
1032 | let _decoded: NoFields = from_slice(&encoded, ctxt).unwrap(); |
1033 | |
1034 | let ctxt = Context::<LE>::new_gvariant(0); |
1035 | let encoded = to_bytes(ctxt, &NoFields {}).unwrap(); |
1036 | assert_eq!(encoded.len(), 1); |
1037 | let _decoded: NoFields = from_slice(&encoded, ctxt).unwrap(); |
1038 | } |
1039 | |
1040 | #[test ] |
1041 | fn struct_ref() { |
1042 | let ctxt = Context::<LE>::new_dbus(0); |
1043 | let encoded = to_bytes(ctxt, &(&1u32, &2u32)).unwrap(); |
1044 | let decoded: [u32; 2] = from_slice(&encoded, ctxt).unwrap(); |
1045 | assert_eq!(decoded, [1u32, 2u32]); |
1046 | } |
1047 | |
1048 | #[test ] |
1049 | fn dict_value() { |
1050 | let mut map: HashMap<i64, &str> = HashMap::new(); |
1051 | map.insert(1, "123" ); |
1052 | map.insert(2, "456" ); |
1053 | let ctxt = Context::<LE>::new_dbus(0); |
1054 | let encoded = to_bytes(ctxt, &map).unwrap(); |
1055 | assert_eq!(dbg!(encoded.len()), 40); |
1056 | let decoded: HashMap<i64, &str> = from_slice(&encoded, ctxt).unwrap(); |
1057 | assert_eq!(decoded[&1], "123" ); |
1058 | assert_eq!(decoded[&2], "456" ); |
1059 | |
1060 | // GVariant format now |
1061 | #[cfg (feature = "gvariant" )] |
1062 | { |
1063 | let ctxt = Context::<NativeEndian>::new_gvariant(0); |
1064 | let gv_encoded = to_bytes(ctxt, &map).unwrap(); |
1065 | assert_eq!(gv_encoded.len(), 30); |
1066 | let map: HashMap<i64, &str> = from_slice(&gv_encoded, ctxt).unwrap(); |
1067 | assert_eq!(map[&1], "123" ); |
1068 | assert_eq!(map[&2], "456" ); |
1069 | |
1070 | // Check encoding against GLib |
1071 | let bytes = Bytes::from_owned(gv_encoded); |
1072 | let variant = Variant::from_bytes::<HashMap<i64, &str>>(&bytes); |
1073 | assert_eq!(variant.n_children(), 2); |
1074 | let map: HashMap<i64, String> = HashMap::from_variant(&variant).unwrap(); |
1075 | assert_eq!(map[&1], "123" ); |
1076 | assert_eq!(map[&2], "456" ); |
1077 | } |
1078 | let ctxt = Context::<LE>::new_dbus(0); |
1079 | |
1080 | // As Value |
1081 | let v: Value<'_> = Dict::from(map).into(); |
1082 | assert_eq!(v.value_signature(), "a{xs}" ); |
1083 | let encoded = to_bytes(ctxt, &v).unwrap(); |
1084 | assert_eq!(encoded.len(), 48); |
1085 | // Convert it back |
1086 | let dict: Dict<'_, '_> = v.try_into().unwrap(); |
1087 | let map: HashMap<i64, String> = dict.try_into().unwrap(); |
1088 | assert_eq!(map[&1], "123" ); |
1089 | assert_eq!(map[&2], "456" ); |
1090 | // Also decode it back |
1091 | let v = from_slice(&encoded, ctxt).unwrap(); |
1092 | if let Value::Dict(dict) = v { |
1093 | assert_eq!(dict.get::<i64, str>(&1).unwrap().unwrap(), "123" ); |
1094 | assert_eq!(dict.get::<i64, str>(&2).unwrap().unwrap(), "456" ); |
1095 | } else { |
1096 | panic!(); |
1097 | } |
1098 | |
1099 | #[cfg (feature = "gvariant" )] |
1100 | { |
1101 | // GVariant-format requires framing offsets for dict entries with variable-length keys |
1102 | // so let's test that. |
1103 | let mut map: HashMap<&str, &str> = HashMap::new(); |
1104 | map.insert("hi" , "1234" ); |
1105 | map.insert("world" , "561" ); |
1106 | let ctxt = Context::<NativeEndian>::new_gvariant(0); |
1107 | let gv_encoded = to_bytes(ctxt, &map).unwrap(); |
1108 | assert_eq!(gv_encoded.len(), 22); |
1109 | let map: HashMap<&str, &str> = from_slice(&gv_encoded, ctxt).unwrap(); |
1110 | assert_eq!(map["hi" ], "1234" ); |
1111 | assert_eq!(map["world" ], "561" ); |
1112 | |
1113 | // Check encoding against GLib |
1114 | let bytes = Bytes::from_owned(gv_encoded); |
1115 | let variant = Variant::from_bytes::<HashMap<&str, &str>>(&bytes); |
1116 | assert_eq!(variant.n_children(), 2); |
1117 | let map: HashMap<String, String> = HashMap::from_variant(&variant).unwrap(); |
1118 | assert_eq!(map["hi" ], "1234" ); |
1119 | assert_eq!(map["world" ], "561" ); |
1120 | |
1121 | // Now the same but empty dict this time |
1122 | let map: HashMap<&str, &str> = HashMap::new(); |
1123 | let gv_encoded = to_bytes(ctxt, &map).unwrap(); |
1124 | assert_eq!(gv_encoded.len(), 0); |
1125 | let map: HashMap<&str, &str> = from_slice(&gv_encoded, ctxt).unwrap(); |
1126 | assert_eq!(map.len(), 0); |
1127 | } |
1128 | let ctxt = Context::<LE>::new_dbus(0); |
1129 | |
1130 | // Now a hand-crafted Dict Value but with a Value as value |
1131 | let mut dict = Dict::new(<&str>::signature(), Value::signature()); |
1132 | dict.add("hello" , Value::new("there" )).unwrap(); |
1133 | dict.add("bye" , Value::new("now" )).unwrap(); |
1134 | let v: Value<'_> = dict.into(); |
1135 | assert_eq!(v.value_signature(), "a{sv}" ); |
1136 | let encoded = to_bytes(ctxt, &v).unwrap(); |
1137 | assert_eq!(dbg!(encoded.len()), 68); |
1138 | let v: Value<'_> = from_slice(&encoded, ctxt).unwrap(); |
1139 | if let Value::Dict(dict) = v { |
1140 | assert_eq!( |
1141 | *dict.get::<_, Value<'_>>("hello" ).unwrap().unwrap(), |
1142 | Value::new("there" ) |
1143 | ); |
1144 | assert_eq!( |
1145 | *dict.get::<_, Value<'_>>("bye" ).unwrap().unwrap(), |
1146 | Value::new("now" ) |
1147 | ); |
1148 | |
1149 | // Try converting to a HashMap |
1150 | let map = <HashMap<String, Value<'_>>>::try_from(dict).unwrap(); |
1151 | assert_eq!(map["hello" ], Value::new("there" )); |
1152 | assert_eq!(map["bye" ], Value::new("now" )); |
1153 | } else { |
1154 | panic!(); |
1155 | } |
1156 | |
1157 | #[derive (SerializeDict, DeserializeDict, Type, PartialEq, Debug)] |
1158 | #[zvariant(signature = "a{sv}" )] |
1159 | struct Test { |
1160 | process_id: Option<u32>, |
1161 | group_id: Option<u32>, |
1162 | user: String, |
1163 | } |
1164 | let test = Test { |
1165 | process_id: Some(42), |
1166 | group_id: None, |
1167 | user: "me" .to_string(), |
1168 | }; |
1169 | |
1170 | let encoded = to_bytes(ctxt, &test ).unwrap(); |
1171 | assert_eq!(encoded.len(), 51); |
1172 | |
1173 | let decoded: HashMap<&str, Value<'_>> = from_slice(&encoded, ctxt).unwrap(); |
1174 | assert_eq!(decoded["process_id" ], Value::U32(42)); |
1175 | assert_eq!(decoded["user" ], Value::new("me" )); |
1176 | assert!(!decoded.contains_key("group_id" )); |
1177 | |
1178 | let decoded: Test = from_slice(&encoded, ctxt).unwrap(); |
1179 | assert_eq!(decoded, test ); |
1180 | |
1181 | #[derive (SerializeDict, DeserializeDict, Type, PartialEq, Debug)] |
1182 | #[zvariant(signature = "a{sv}" )] |
1183 | struct TestMissing { |
1184 | process_id: Option<u32>, |
1185 | group_id: Option<u32>, |
1186 | user: String, |
1187 | quota: u8, |
1188 | } |
1189 | let decoded: Result<TestMissing> = from_slice(&encoded, ctxt); |
1190 | assert_eq!( |
1191 | decoded.unwrap_err(), |
1192 | Error::Message("missing field `quota`" .to_string()) |
1193 | ); |
1194 | |
1195 | #[derive (SerializeDict, DeserializeDict, Type, PartialEq, Debug)] |
1196 | #[zvariant(signature = "a{sv}" )] |
1197 | struct TestSkipUnknown { |
1198 | process_id: Option<u32>, |
1199 | group_id: Option<u32>, |
1200 | } |
1201 | let _: TestSkipUnknown = from_slice(&encoded, ctxt).unwrap(); |
1202 | |
1203 | #[derive (SerializeDict, DeserializeDict, Type, PartialEq, Debug)] |
1204 | #[zvariant(deny_unknown_fields, signature = "a{sv}" )] |
1205 | struct TestUnknown { |
1206 | process_id: Option<u32>, |
1207 | group_id: Option<u32>, |
1208 | } |
1209 | let decoded: Result<TestUnknown> = from_slice(&encoded, ctxt); |
1210 | assert_eq!( |
1211 | decoded.unwrap_err(), |
1212 | Error::Message("unknown field `user`, expected `process_id` or `group_id`" .to_string()) |
1213 | ); |
1214 | } |
1215 | |
1216 | #[test ] |
1217 | fn value_value() { |
1218 | let ctxt = Context::<BE>::new_dbus(0); |
1219 | let encoded = to_bytes(ctxt, &0xABBA_ABBA_ABBA_ABBA_u64).unwrap(); |
1220 | assert_eq!(encoded.len(), 8); |
1221 | assert_eq!(LE::read_u64(&encoded), 0xBAAB_BAAB_BAAB_BAAB_u64); |
1222 | let decoded: u64 = from_slice(&encoded, ctxt).unwrap(); |
1223 | assert_eq!(decoded, 0xABBA_ABBA_ABBA_ABBA); |
1224 | |
1225 | // Lie about there being bytes before |
1226 | let ctxt = Context::<LE>::new_dbus(2); |
1227 | let encoded = to_bytes(ctxt, &0xABBA_ABBA_ABBA_ABBA_u64).unwrap(); |
1228 | assert_eq!(encoded.len(), 14); |
1229 | let decoded: u64 = from_slice(&encoded, ctxt).unwrap(); |
1230 | assert_eq!(decoded, 0xABBA_ABBA_ABBA_ABBA_u64); |
1231 | let ctxt = Context::<LE>::new_dbus(0); |
1232 | |
1233 | // As Value |
1234 | let v: Value<'_> = 0xFEFE_u64.into(); |
1235 | assert_eq!(v.value_signature(), "t" ); |
1236 | let encoded = to_bytes(ctxt, &v).unwrap(); |
1237 | assert_eq!(encoded.len(), 16); |
1238 | let v = from_slice(&encoded, ctxt).unwrap(); |
1239 | assert_eq!(v, Value::U64(0xFEFE)); |
1240 | |
1241 | // And now as Value in a Value |
1242 | let v = Value::Value(Box::new(v)); |
1243 | let encoded = to_bytes(ctxt, &v).unwrap(); |
1244 | assert_eq!(encoded.len(), 16); |
1245 | let v = from_slice(&encoded, ctxt).unwrap(); |
1246 | if let Value::Value(v) = v { |
1247 | assert_eq!(v.value_signature(), "t" ); |
1248 | assert_eq!(*v, Value::U64(0xFEFE)); |
1249 | } else { |
1250 | panic!(); |
1251 | } |
1252 | |
1253 | // Ensure Value works with other Serializer & Deserializer |
1254 | let v: Value<'_> = 0xFEFE_u64.into(); |
1255 | let encoded = serde_json::to_string(&v).unwrap(); |
1256 | let v = serde_json::from_str::<Value<'_>>(&encoded).unwrap(); |
1257 | assert_eq!(v, Value::U64(0xFEFE)); |
1258 | } |
1259 | |
1260 | #[test ] |
1261 | fn enums() { |
1262 | use serde::{Deserialize, Serialize}; |
1263 | |
1264 | #[derive (Debug, PartialEq, Eq, Serialize, Deserialize)] |
1265 | enum Unit { |
1266 | Variant1, |
1267 | Variant2, |
1268 | Variant3, |
1269 | } |
1270 | |
1271 | let ctxts_n_expected_lens = [ |
1272 | // Unit variants are encoded as u32 and that has the same encoding in both formats. |
1273 | [ |
1274 | (Context::<BE>::new_dbus(0), 4usize), |
1275 | (Context::<BE>::new_dbus(1), 7), |
1276 | (Context::<BE>::new_dbus(2), 6), |
1277 | (Context::<BE>::new_dbus(3), 5), |
1278 | (Context::<BE>::new_dbus(4), 4), |
1279 | ], |
1280 | #[cfg (feature = "gvariant" )] |
1281 | [ |
1282 | (Context::<BE>::new_gvariant(0), 4usize), |
1283 | (Context::<BE>::new_gvariant(1), 7), |
1284 | (Context::<BE>::new_gvariant(2), 6), |
1285 | (Context::<BE>::new_gvariant(3), 5), |
1286 | (Context::<BE>::new_gvariant(4), 4), |
1287 | ], |
1288 | ]; |
1289 | let signature = "u" .try_into().unwrap(); |
1290 | for ctxts_n_expected_len in ctxts_n_expected_lens { |
1291 | for (ctxt, expected_len) in ctxts_n_expected_len { |
1292 | let encoded = to_bytes_for_signature(ctxt, &signature, &Unit::Variant2).unwrap(); |
1293 | assert_eq!(encoded.len(), expected_len); |
1294 | let decoded: Unit = from_slice_for_signature(&encoded, ctxt, &signature).unwrap(); |
1295 | assert_eq!(decoded, Unit::Variant2); |
1296 | } |
1297 | } |
1298 | |
1299 | #[derive (Debug, PartialEq, Eq, Serialize, Deserialize)] |
1300 | enum NewType<'s> { |
1301 | Variant1(&'s str), |
1302 | Variant2(&'s str), |
1303 | Variant3(&'s str), |
1304 | } |
1305 | |
1306 | let ctxts_n_expected_lens = [ |
1307 | [ |
1308 | (Context::<BE>::new_dbus(0), 14usize), |
1309 | (Context::<BE>::new_dbus(1), 21), |
1310 | (Context::<BE>::new_dbus(2), 20), |
1311 | (Context::<BE>::new_dbus(3), 19), |
1312 | (Context::<BE>::new_dbus(4), 18), |
1313 | ], |
1314 | #[cfg (feature = "gvariant" )] |
1315 | [ |
1316 | (Context::<BE>::new_gvariant(0), 10usize), |
1317 | (Context::<BE>::new_gvariant(1), 13), |
1318 | (Context::<BE>::new_gvariant(2), 12), |
1319 | (Context::<BE>::new_gvariant(3), 11), |
1320 | (Context::<BE>::new_gvariant(4), 10), |
1321 | ], |
1322 | ]; |
1323 | let signature = "(us)" .try_into().unwrap(); |
1324 | for ctxts_n_expected_len in ctxts_n_expected_lens { |
1325 | for (ctxt, expected_len) in ctxts_n_expected_len { |
1326 | let encoded = |
1327 | to_bytes_for_signature(ctxt, &signature, &NewType::Variant2("hello" )).unwrap(); |
1328 | assert_eq!(encoded.len(), expected_len); |
1329 | let decoded: NewType<'_> = |
1330 | from_slice_for_signature(&encoded, ctxt, &signature).unwrap(); |
1331 | assert_eq!(decoded, NewType::Variant2("hello" )); |
1332 | } |
1333 | } |
1334 | |
1335 | #[derive (Debug, PartialEq, Eq, Serialize, Deserialize)] |
1336 | enum Structs { |
1337 | Tuple(u8, u32), |
1338 | Struct { y: u8, t: u32 }, |
1339 | } |
1340 | |
1341 | let ctxts_n_expected_lens = [ |
1342 | [ |
1343 | (Context::<BE>::new_dbus(0), 16usize), |
1344 | (Context::<BE>::new_dbus(1), 23), |
1345 | (Context::<BE>::new_dbus(2), 22), |
1346 | (Context::<BE>::new_dbus(3), 21), |
1347 | (Context::<BE>::new_dbus(4), 20), |
1348 | ], |
1349 | #[cfg (feature = "gvariant" )] |
1350 | [ |
1351 | (Context::<BE>::new_gvariant(0), 12usize), |
1352 | (Context::<BE>::new_gvariant(1), 15), |
1353 | (Context::<BE>::new_gvariant(2), 14), |
1354 | (Context::<BE>::new_gvariant(3), 13), |
1355 | (Context::<BE>::new_gvariant(4), 12), |
1356 | ], |
1357 | ]; |
1358 | // TODO: Provide convenience API to create complex signatures |
1359 | let signature = "(u(yu))" .try_into().unwrap(); |
1360 | for ctxts_n_expected_len in ctxts_n_expected_lens { |
1361 | for (ctxt, expected_len) in ctxts_n_expected_len { |
1362 | let encoded = |
1363 | to_bytes_for_signature(ctxt, &signature, &Structs::Tuple(42, 42)).unwrap(); |
1364 | assert_eq!(encoded.len(), expected_len); |
1365 | let decoded: Structs = |
1366 | from_slice_for_signature(&encoded, ctxt, &signature).unwrap(); |
1367 | assert_eq!(decoded, Structs::Tuple(42, 42)); |
1368 | |
1369 | let s = Structs::Struct { y: 42, t: 42 }; |
1370 | let encoded = to_bytes_for_signature(ctxt, &signature, &s).unwrap(); |
1371 | assert_eq!(encoded.len(), expected_len); |
1372 | let decoded: Structs = |
1373 | from_slice_for_signature(&encoded, ctxt, &signature).unwrap(); |
1374 | assert_eq!(decoded, Structs::Struct { y: 42, t: 42 }); |
1375 | } |
1376 | } |
1377 | } |
1378 | |
1379 | #[test ] |
1380 | fn derive() { |
1381 | use serde::{Deserialize, Serialize}; |
1382 | use serde_repr::{Deserialize_repr, Serialize_repr}; |
1383 | |
1384 | #[derive (Deserialize, Serialize, Type, PartialEq, Debug)] |
1385 | struct Struct<'s> { |
1386 | field1: u16, |
1387 | field2: i64, |
1388 | field3: &'s str, |
1389 | } |
1390 | |
1391 | assert_eq!(Struct::signature(), "(qxs)" ); |
1392 | let s = Struct { |
1393 | field1: 0xFF_FF, |
1394 | field2: 0xFF_FF_FF_FF_FF_FF, |
1395 | field3: "hello" , |
1396 | }; |
1397 | let ctxt = Context::<LE>::new_dbus(0); |
1398 | let encoded = to_bytes(ctxt, &s).unwrap(); |
1399 | assert_eq!(encoded.len(), 26); |
1400 | let decoded: Struct<'_> = from_slice(&encoded, ctxt).unwrap(); |
1401 | assert_eq!(decoded, s); |
1402 | |
1403 | #[derive (Deserialize, Serialize, Type)] |
1404 | struct UnitStruct; |
1405 | |
1406 | assert_eq!(UnitStruct::signature(), <()>::signature()); |
1407 | let encoded = to_bytes(ctxt, &UnitStruct).unwrap(); |
1408 | assert_eq!(encoded.len(), 0); |
1409 | let _: UnitStruct = from_slice(&encoded, ctxt).unwrap(); |
1410 | |
1411 | #[repr (u8)] |
1412 | #[derive (Deserialize_repr, Serialize_repr, Type, Debug, PartialEq)] |
1413 | enum Enum { |
1414 | Variant1, |
1415 | Variant2, |
1416 | Variant3, |
1417 | } |
1418 | |
1419 | assert_eq!(Enum::signature(), u8::signature()); |
1420 | let encoded = to_bytes(ctxt, &Enum::Variant3).unwrap(); |
1421 | assert_eq!(encoded.len(), 1); |
1422 | let decoded: Enum = from_slice(&encoded, ctxt).unwrap(); |
1423 | assert_eq!(decoded, Enum::Variant3); |
1424 | |
1425 | #[repr (i64)] |
1426 | #[derive (Deserialize_repr, Serialize_repr, Type, Debug, PartialEq)] |
1427 | enum Enum2 { |
1428 | Variant1, |
1429 | Variant2, |
1430 | Variant3, |
1431 | } |
1432 | |
1433 | assert_eq!(Enum2::signature(), i64::signature()); |
1434 | let encoded = to_bytes(ctxt, &Enum2::Variant2).unwrap(); |
1435 | assert_eq!(encoded.len(), 8); |
1436 | let decoded: Enum2 = from_slice(&encoded, ctxt).unwrap(); |
1437 | assert_eq!(decoded, Enum2::Variant2); |
1438 | |
1439 | #[derive (Deserialize, Serialize, Type, Debug, PartialEq)] |
1440 | enum NoReprEnum { |
1441 | Variant1, |
1442 | Variant2, |
1443 | Variant3, |
1444 | } |
1445 | |
1446 | // issue#265: Panic on deserialization of a structure w/ a unit enum as its last field. |
1447 | let encoded = to_bytes(ctxt, &(NoReprEnum::Variant2,)).unwrap(); |
1448 | let _: (NoReprEnum,) = from_slice(&encoded, ctxt).unwrap(); |
1449 | |
1450 | assert_eq!(NoReprEnum::signature(), u32::signature()); |
1451 | let encoded = to_bytes(ctxt, &NoReprEnum::Variant2).unwrap(); |
1452 | assert_eq!(encoded.len(), 4); |
1453 | let decoded: NoReprEnum = from_slice(&encoded, ctxt).unwrap(); |
1454 | assert_eq!(decoded, NoReprEnum::Variant2); |
1455 | |
1456 | #[derive (Deserialize, Serialize, Type, Debug, PartialEq)] |
1457 | #[zvariant(signature = "s" )] |
1458 | enum StrEnum { |
1459 | Variant1, |
1460 | Variant2, |
1461 | Variant3, |
1462 | } |
1463 | |
1464 | assert_eq!(StrEnum::signature(), <&str>::signature()); |
1465 | let encoded = to_bytes(ctxt, &StrEnum::Variant2).unwrap(); |
1466 | assert_eq!(encoded.len(), 13); |
1467 | let decoded: StrEnum = from_slice(&encoded, ctxt).unwrap(); |
1468 | assert_eq!(decoded, StrEnum::Variant2); |
1469 | |
1470 | #[derive (Deserialize, Serialize, Type)] |
1471 | enum NewType { |
1472 | Variant1(f64), |
1473 | Variant2(f64), |
1474 | } |
1475 | assert_eq!(NewType::signature(), "(ud)" ); |
1476 | |
1477 | #[derive (Deserialize, Serialize, Type)] |
1478 | enum StructFields { |
1479 | Variant1(u16, i64, &'static str), |
1480 | Variant2 { |
1481 | field1: u16, |
1482 | field2: i64, |
1483 | field3: &'static str, |
1484 | }, |
1485 | } |
1486 | assert_eq!(StructFields::signature(), "(u(qxs))" ); |
1487 | |
1488 | #[derive (Deserialize, Serialize, Type, PartialEq, Debug)] |
1489 | struct AStruct<'s> { |
1490 | field1: u16, |
1491 | field2: &'s [u8], |
1492 | field3: &'s [u8], |
1493 | field4: i64, |
1494 | } |
1495 | assert_eq!(AStruct::signature(), "(qayayx)" ); |
1496 | let s = AStruct { |
1497 | field1: 0xFF_FF, |
1498 | field2: &[77u8; 8], |
1499 | field3: &[77u8; 8], |
1500 | field4: 0xFF_FF_FF_FF_FF_FF, |
1501 | }; |
1502 | let encoded = to_bytes(ctxt, &s).unwrap(); |
1503 | assert_eq!(encoded.len(), 40); |
1504 | let decoded: AStruct<'_> = from_slice(&encoded, ctxt).unwrap(); |
1505 | assert_eq!(decoded, s); |
1506 | } |
1507 | |
1508 | #[test ] |
1509 | fn serialized_size() { |
1510 | let ctxt = Context::<LE>::new_dbus(0); |
1511 | let l = crate::serialized_size(ctxt, &()).unwrap(); |
1512 | assert_eq!(l, 0); |
1513 | |
1514 | #[cfg (unix)] |
1515 | { |
1516 | let stdout = std::io::stdout(); |
1517 | let l = crate::serialized_size_fds(ctxt, &Fd::from(&stdout)).unwrap(); |
1518 | assert_eq!(l, (4, 1)); |
1519 | } |
1520 | |
1521 | let l = crate::serialized_size(ctxt, &('a' , "abc" , &(1_u32, 2))).unwrap(); |
1522 | assert_eq!(l, 24); |
1523 | |
1524 | let v = vec![1, 2]; |
1525 | let l = crate::serialized_size(ctxt, &('a' , "abc" , &v)).unwrap(); |
1526 | assert_eq!(l, 28); |
1527 | } |
1528 | |
1529 | #[test ] |
1530 | #[cfg (feature = "serde_bytes" )] |
1531 | fn serde_bytes() { |
1532 | use serde::{Deserialize, Serialize}; |
1533 | use serde_bytes::*; |
1534 | |
1535 | let ctxt = Context::<LE>::new_dbus(0); |
1536 | let ay = Bytes::new(&[77u8; 1_000_000]); |
1537 | let encoded = to_bytes(ctxt, &ay).unwrap(); |
1538 | assert_eq!(encoded.len(), 1_000_004); |
1539 | let decoded: ByteBuf = from_slice(&encoded, ctxt).unwrap(); |
1540 | assert_eq!(decoded.len(), 1_000_000); |
1541 | |
1542 | #[derive (Deserialize, Serialize, Type, PartialEq, Debug)] |
1543 | struct Struct<'s> { |
1544 | field1: u16, |
1545 | #[serde(with = "serde_bytes" )] |
1546 | field2: &'s [u8], |
1547 | field3: i64, |
1548 | } |
1549 | assert_eq!(Struct::signature(), "(qayx)" ); |
1550 | let s = Struct { |
1551 | field1: 0xFF_FF, |
1552 | field2: &[77u8; 512], |
1553 | field3: 0xFF_FF_FF_FF_FF_FF, |
1554 | }; |
1555 | let encoded = to_bytes(ctxt, &s).unwrap(); |
1556 | assert_eq!(encoded.len(), 528); |
1557 | let decoded: Struct<'_> = from_slice(&encoded, ctxt).unwrap(); |
1558 | assert_eq!(decoded, s); |
1559 | } |
1560 | |
1561 | #[test ] |
1562 | #[cfg (all(feature = "serde_bytes" , feature = "gvariant" ))] |
1563 | fn serde_bytes_gvariant() { |
1564 | use serde::{Deserialize, Serialize}; |
1565 | use serde_bytes::*; |
1566 | |
1567 | let ctxt = Context::<LE>::new_gvariant(0); |
1568 | let ay = Bytes::new(&[77u8; 1_000_000]); |
1569 | let encoded = to_bytes(ctxt, &ay).unwrap(); |
1570 | assert_eq!(encoded.len(), 1_000_000); |
1571 | let decoded: ByteBuf = from_slice(&encoded, ctxt).unwrap(); |
1572 | assert_eq!(decoded.len(), 1_000_000); |
1573 | |
1574 | #[derive (Deserialize, Serialize, Type, PartialEq, Debug)] |
1575 | struct Struct<'s> { |
1576 | field1: u16, |
1577 | #[serde(with = "serde_bytes" )] |
1578 | field2: &'s [u8], |
1579 | field3: i64, |
1580 | } |
1581 | assert_eq!(Struct::signature(), "(qayx)" ); |
1582 | let s = Struct { |
1583 | field1: 0xFF_FF, |
1584 | field2: &[77u8; 512], |
1585 | field3: 0xFF_FF_FF_FF_FF_FF, |
1586 | }; |
1587 | let encoded = to_bytes(ctxt, &s).unwrap(); |
1588 | assert_eq!(encoded.len(), 530); |
1589 | let decoded: Struct<'_> = from_slice(&encoded, ctxt).unwrap(); |
1590 | assert_eq!(decoded, s); |
1591 | } |
1592 | |
1593 | #[test ] |
1594 | #[cfg (feature = "gvariant" )] |
1595 | fn option_value() { |
1596 | let ctxt = Context::<NativeEndian>::new_gvariant(0); |
1597 | |
1598 | // First a Some fixed-sized value |
1599 | let mn = Some(16i16); |
1600 | let encoded = to_bytes(ctxt, &mn).unwrap(); |
1601 | assert_eq!(encoded.len(), 2); |
1602 | let decoded: Option<i16> = from_slice(&encoded, ctxt).unwrap(); |
1603 | assert_eq!(decoded, mn); |
1604 | |
1605 | // Check encoding against GLib |
1606 | let bytes = Bytes::from_owned(encoded); |
1607 | let variant = Variant::from_bytes::<Option<i16>>(&bytes); |
1608 | assert_eq!(variant.get::<Option<i16>>().unwrap(), mn); |
1609 | |
1610 | // As Value |
1611 | let v: Value<'_> = mn.into(); |
1612 | let encoded = to_bytes(ctxt, &v).unwrap(); |
1613 | assert_eq!(encoded.len(), 5); |
1614 | let decoded: Value<'_> = from_slice(&encoded, ctxt).unwrap(); |
1615 | if let Value::Maybe(maybe) = decoded { |
1616 | assert_eq!(maybe.get().unwrap(), mn); |
1617 | } else { |
1618 | panic!(); |
1619 | } |
1620 | |
1621 | // Check encoding against GLib |
1622 | let bytes = Bytes::from_owned(encoded); |
1623 | let variant = Variant::from_bytes::<Variant>(&bytes); |
1624 | let decoded = variant.child_value(0).get::<Option<i16>>().unwrap(); |
1625 | assert_eq!(decoded, mn); |
1626 | |
1627 | // Now a None of the same type |
1628 | let mn: Option<i16> = None; |
1629 | let encoded = to_bytes(ctxt, &mn).unwrap(); |
1630 | assert_eq!(encoded.len(), 0); |
1631 | let decoded: Option<i16> = from_slice(&encoded, ctxt).unwrap(); |
1632 | assert!(decoded.is_none()); |
1633 | |
1634 | // Check encoding against GLib |
1635 | let bytes = Bytes::from_owned(encoded); |
1636 | let variant = Variant::from_bytes::<Option<i16>>(&bytes); |
1637 | assert!(variant.get::<Option<i16>>().unwrap().is_none()); |
1638 | |
1639 | // Next a Some variable-sized value |
1640 | let ms = Some("hello world" ); |
1641 | let encoded = to_bytes(ctxt, &ms).unwrap(); |
1642 | assert_eq!(encoded.len(), 13); |
1643 | let decoded: Option<&str> = from_slice(&encoded, ctxt).unwrap(); |
1644 | assert_eq!(decoded, ms); |
1645 | |
1646 | // Check encoding against GLib |
1647 | let bytes = Bytes::from_owned(encoded); |
1648 | let variant = Variant::from_bytes::<Option<String>>(&bytes); |
1649 | assert_eq!( |
1650 | &variant.get::<Option<String>>().unwrap().unwrap(), |
1651 | ms.unwrap() |
1652 | ); |
1653 | |
1654 | // As Value |
1655 | let v: Value<'_> = ms.into(); |
1656 | let encoded = to_bytes(ctxt, &v).unwrap(); |
1657 | assert_eq!(encoded.len(), 16); |
1658 | let decoded: Value<'_> = from_slice(&encoded, ctxt).unwrap(); |
1659 | if let Value::Maybe(maybe) = decoded { |
1660 | assert_eq!(maybe.get::<String>().unwrap().as_deref(), ms); |
1661 | } else { |
1662 | panic!(); |
1663 | } |
1664 | |
1665 | // Check encoding against GLib |
1666 | let bytes = Bytes::from_owned(encoded); |
1667 | let variant = Variant::from_bytes::<Variant>(&bytes); |
1668 | let decoded = variant.child_value(0).get::<Option<String>>().unwrap(); |
1669 | assert_eq!(decoded.as_deref(), ms); |
1670 | |
1671 | // Now a None of the same type |
1672 | let ms: Option<&str> = None; |
1673 | let encoded = to_bytes(ctxt, &ms).unwrap(); |
1674 | assert_eq!(encoded.len(), 0); |
1675 | let decoded: Option<&str> = from_slice(&encoded, ctxt).unwrap(); |
1676 | assert!(decoded.is_none()); |
1677 | |
1678 | // Check encoding against GLib |
1679 | let bytes = Bytes::from_owned(encoded); |
1680 | let variant = Variant::from_bytes::<Option<String>>(&bytes); |
1681 | assert!(variant.get::<Option<String>>().unwrap().is_none()); |
1682 | |
1683 | // In a seq type |
1684 | let ams = vec![ |
1685 | Some(String::from("hello world" )), |
1686 | Some(String::from("bye world" )), |
1687 | ]; |
1688 | let encoded = to_bytes(ctxt, &ams).unwrap(); |
1689 | assert_eq!(encoded.len(), 26); |
1690 | let decoded: Vec<Option<String>> = from_slice(&encoded, ctxt).unwrap(); |
1691 | assert_eq!(decoded, ams); |
1692 | |
1693 | // Check encoding against GLib |
1694 | let bytes = Bytes::from_owned(encoded); |
1695 | let variant = Variant::from_bytes::<Vec<Option<String>>>(&bytes); |
1696 | let decoded = variant.get::<Vec<Option<String>>>().unwrap(); |
1697 | assert_eq!(decoded, ams); |
1698 | |
1699 | // As Value |
1700 | let v: Value<'_> = ams.clone().into(); |
1701 | let encoded = to_bytes(ctxt, &v).unwrap(); |
1702 | assert_eq!(encoded.len(), 30); |
1703 | let decoded: Value<'_> = from_slice(&encoded, ctxt).unwrap(); |
1704 | assert_eq!(v, decoded); |
1705 | |
1706 | // Check encoding against GLib |
1707 | let bytes = Bytes::from_owned(encoded); |
1708 | let variant = Variant::from_bytes::<Variant>(&bytes); |
1709 | let decoded = variant.child_value(0).get::<Vec<Option<String>>>().unwrap(); |
1710 | assert_eq!(decoded, ams); |
1711 | |
1712 | // In a struct |
1713 | let structure: (Option<String>, u64, Option<String>) = |
1714 | (Some(String::from("hello world" )), 42u64, None); |
1715 | let encoded = to_bytes(ctxt, &structure).unwrap(); |
1716 | assert_eq!(encoded.len(), 25); |
1717 | let decoded: (Option<String>, u64, Option<String>) = from_slice(&encoded, ctxt).unwrap(); |
1718 | assert_eq!(decoded, structure); |
1719 | |
1720 | // Check encoding against GLib |
1721 | let bytes = Bytes::from_owned(encoded); |
1722 | let variant = Variant::from_bytes::<(Option<String>, u64, Option<String>)>(&bytes); |
1723 | let decoded = variant |
1724 | .get::<(Option<String>, u64, Option<String>)>() |
1725 | .unwrap(); |
1726 | assert_eq!(decoded, structure); |
1727 | |
1728 | // As Value |
1729 | let v: Value<'_> = structure.clone().into(); |
1730 | let encoded = to_bytes(ctxt, &v).unwrap(); |
1731 | assert_eq!(encoded.len(), 33); |
1732 | let decoded: Value<'_> = from_slice(&encoded, ctxt).unwrap(); |
1733 | assert_eq!(v, decoded); |
1734 | |
1735 | // Check encoding against GLib |
1736 | let bytes = Bytes::from_owned(encoded); |
1737 | let variant = Variant::from_bytes::<Variant>(&bytes); |
1738 | let decoded = variant |
1739 | .child_value(0) |
1740 | .get::<(Option<String>, u64, Option<String>)>() |
1741 | .unwrap(); |
1742 | assert_eq!(decoded, structure); |
1743 | } |
1744 | |
1745 | #[test ] |
1746 | fn struct_with_hashmap() { |
1747 | use serde::{Deserialize, Serialize}; |
1748 | |
1749 | let mut hmap = HashMap::new(); |
1750 | hmap.insert("key" .into(), "value" .into()); |
1751 | |
1752 | #[derive (Type, Deserialize, Serialize, PartialEq, Debug)] |
1753 | struct Foo { |
1754 | hmap: HashMap<String, String>, |
1755 | } |
1756 | |
1757 | let foo = Foo { hmap }; |
1758 | assert_eq!(Foo::signature(), "(a{ss})" ); |
1759 | |
1760 | let ctxt = Context::<LE>::new_dbus(0); |
1761 | let encoded = to_bytes(ctxt, &(&foo, 1)).unwrap(); |
1762 | let f: Foo = from_slice(&encoded, ctxt).unwrap(); |
1763 | assert_eq!(f, foo); |
1764 | } |
1765 | |
1766 | #[test ] |
1767 | fn issue_59() { |
1768 | // Ensure we don't panic on deserializing tuple of smaller than expected length. |
1769 | let ctxt = Context::<LE>::new_dbus(0); |
1770 | let encoded = to_bytes(ctxt, &("hello" ,)).unwrap(); |
1771 | let result: Result<(&str, &str)> = from_slice(&encoded, ctxt); |
1772 | assert!(result.is_err()); |
1773 | } |
1774 | |
1775 | #[test ] |
1776 | #[cfg (feature = "gvariant" )] |
1777 | fn issue_99() { |
1778 | #[derive (Deserialize, Serialize, Type, PartialEq, Debug)] |
1779 | struct ZVStruct<'s>(#[serde(borrow)] HashMap<&'s str, Value<'s>>); |
1780 | |
1781 | let mut dict = HashMap::new(); |
1782 | dict.insert("hi" , Value::from("hello" )); |
1783 | dict.insert("bye" , Value::from("then" )); |
1784 | |
1785 | let element = ZVStruct(dict); |
1786 | |
1787 | let ctxt = Context::<LE>::new_gvariant(0); |
1788 | let signature = ZVStruct::signature(); |
1789 | |
1790 | let encoded = to_bytes_for_signature(ctxt, &signature, &element).unwrap(); |
1791 | let _: ZVStruct<'_> = from_slice_for_signature(&encoded, ctxt, &signature).unwrap(); |
1792 | } |
1793 | |
1794 | #[test ] |
1795 | fn ip_addr() { |
1796 | let ctxt = Context::<LE>::new_dbus(0); |
1797 | |
1798 | // First the bare specific types. |
1799 | let localhost_v4 = Ipv4Addr::new(127, 0, 0, 1); |
1800 | let encoded = to_bytes(ctxt, &localhost_v4).unwrap(); |
1801 | let decoded: Ipv4Addr = from_slice(&encoded, ctxt).unwrap(); |
1802 | assert_eq!(localhost_v4, decoded); |
1803 | |
1804 | let localhost_v6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); |
1805 | let encoded = to_bytes(ctxt, &localhost_v6).unwrap(); |
1806 | let decoded: Ipv6Addr = from_slice(&encoded, ctxt).unwrap(); |
1807 | assert_eq!(localhost_v6, decoded); |
1808 | |
1809 | // Now wrapper under the generic IpAddr. |
1810 | let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); |
1811 | let encoded = to_bytes(ctxt, &localhost_v4).unwrap(); |
1812 | let decoded: IpAddr = from_slice(&encoded, ctxt).unwrap(); |
1813 | assert_eq!(localhost_v4, decoded); |
1814 | |
1815 | let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); |
1816 | let encoded = to_bytes(ctxt, &localhost_v6).unwrap(); |
1817 | let decoded: IpAddr = from_slice(&encoded, ctxt).unwrap(); |
1818 | assert_eq!(localhost_v6, decoded); |
1819 | } |
1820 | |
1821 | #[cfg (feature = "ostree-tests" )] |
1822 | #[test ] |
1823 | fn ostree_de() { |
1824 | #[derive (Deserialize, Serialize, Type, PartialEq, Debug)] |
1825 | struct Summary<'a>(Vec<Repo<'a>>, #[serde(borrow)] HashMap<&'a str, Value<'a>>); |
1826 | |
1827 | #[derive (Deserialize, Serialize, Type, PartialEq, Debug)] |
1828 | struct Repo<'a>(&'a str, #[serde(borrow)] Metadata<'a>); |
1829 | |
1830 | #[derive (Deserialize, Serialize, Type, PartialEq, Debug)] |
1831 | struct Metadata<'a>(u64, Vec<u8>, #[serde(borrow)] HashMap<&'a str, Value<'a>>); |
1832 | |
1833 | let encoded = std::fs::read("../test-data/flatpak-summary.dump" ).unwrap(); |
1834 | let ctxt = Context::<LE>::new_gvariant(0); |
1835 | let _: Summary<'_> = from_slice(&encoded, ctxt).unwrap(); |
1836 | // If we're able to deserialize all the data successfully, don't bother checking the summary |
1837 | // data. |
1838 | } |
1839 | |
1840 | #[test ] |
1841 | #[cfg (feature = "time" )] |
1842 | fn time() { |
1843 | // time::Date |
1844 | let date = time::Date::from_calendar_date(2011, time::Month::June, 21).unwrap(); |
1845 | let ctxt = Context::<LE>::new_dbus(0); |
1846 | let encoded = to_bytes(ctxt, &date).unwrap(); |
1847 | let decoded: time::Date = from_slice(&encoded, ctxt).unwrap(); |
1848 | assert_eq!(date, decoded); |
1849 | |
1850 | // time::Duration |
1851 | let duration = time::Duration::new(42, 123456789); |
1852 | let ctxt = Context::<LE>::new_dbus(0); |
1853 | let encoded = to_bytes(ctxt, &duration).unwrap(); |
1854 | let decoded: time::Duration = from_slice(&encoded, ctxt).unwrap(); |
1855 | assert_eq!(duration, decoded); |
1856 | |
1857 | // time::OffsetDateTime |
1858 | let offset = time::OffsetDateTime::now_utc(); |
1859 | let ctxt = Context::<LE>::new_dbus(0); |
1860 | let encoded = to_bytes(ctxt, &offset).unwrap(); |
1861 | let decoded: time::OffsetDateTime = from_slice(&encoded, ctxt).unwrap(); |
1862 | assert_eq!(offset, decoded); |
1863 | |
1864 | // time::Time |
1865 | let time = time::Time::from_hms(23, 42, 59).unwrap(); |
1866 | let ctxt = Context::<LE>::new_dbus(0); |
1867 | let encoded = to_bytes(ctxt, &time).unwrap(); |
1868 | let decoded: time::Time = from_slice(&encoded, ctxt).unwrap(); |
1869 | assert_eq!(time, decoded); |
1870 | |
1871 | // time::PrimitiveDateTime |
1872 | let date = time::PrimitiveDateTime::new(date, time); |
1873 | let ctxt = Context::<LE>::new_dbus(0); |
1874 | let encoded = to_bytes(ctxt, &date).unwrap(); |
1875 | let decoded: time::PrimitiveDateTime = from_slice(&encoded, ctxt).unwrap(); |
1876 | assert_eq!(date, decoded); |
1877 | } |
1878 | |
1879 | #[test ] |
1880 | fn recursion_limits() { |
1881 | let ctxt = Context::<LE>::new_dbus(0); |
1882 | // Total container depth exceeds limit (64) |
1883 | let mut value = Value::from(0u8); |
1884 | for _ in 0..64 { |
1885 | value = Value::Value(Box::new(value)); |
1886 | } |
1887 | assert!(matches!( |
1888 | to_bytes(ctxt, &value), |
1889 | Err(Error::MaxDepthExceeded(MaxDepthExceeded::Container)) |
1890 | )); |
1891 | |
1892 | // Array depth exceeds limit (32) |
1893 | let vec = vec![vec![vec![vec![vec![vec![vec![vec![vec![vec![vec![ |
1894 | vec![vec![vec![vec![vec![vec![vec![vec![vec![vec![vec![ |
1895 | vec![vec![vec![vec![vec![vec![vec![vec![vec![vec![vec![ |
1896 | 0u8, |
1897 | ]]]]]]]]]]], |
1898 | ]]]]]]]]]]], |
1899 | ]]]]]]]]]]]; |
1900 | assert!(matches!( |
1901 | to_bytes(ctxt, &vec), |
1902 | Err(Error::MaxDepthExceeded(MaxDepthExceeded::Array)) |
1903 | )); |
1904 | |
1905 | // Struct depth exceeds limit (32) |
1906 | let tuple = (((((((((((((((((((((( |
1907 | (((((((((((0u8,),),),),),),),),),),), |
1908 | ),),),),),),),),),),),),),),),),),),),),),); |
1909 | assert!(matches!( |
1910 | to_bytes(ctxt, &tuple), |
1911 | Err(Error::MaxDepthExceeded(MaxDepthExceeded::Structure)) |
1912 | )); |
1913 | |
1914 | // total depth exceeds limit (64) with struct, array and variant. |
1915 | let mut value = Value::from(0u8); |
1916 | for _ in 0..32 { |
1917 | value = Value::Value(Box::new(value)); |
1918 | } |
1919 | let tuple_array = |
1920 | ( |
1921 | ((((((((((((((((vec![vec![vec![vec![vec![vec![vec![vec![ |
1922 | vec![vec![vec![vec![vec![vec![vec![vec![value]]]]]]]], |
1923 | ]]]]]]]],),),),),),),),),),),),),),),),), |
1924 | ); |
1925 | assert!(matches!( |
1926 | to_bytes(ctxt, &tuple_array), |
1927 | Err(Error::MaxDepthExceeded(MaxDepthExceeded::Container)) |
1928 | )); |
1929 | |
1930 | // TODO: |
1931 | // |
1932 | // * Test deserializers. |
1933 | // * Test gvariant format. |
1934 | } |
1935 | } |
1936 | |