1 | use core::{ |
2 | cmp::Ordering, |
3 | fmt::{Display, Write}, |
4 | hash::{Hash, Hasher}, |
5 | marker::PhantomData, |
6 | mem::discriminant, |
7 | str, |
8 | }; |
9 | |
10 | use serde::{ |
11 | de::{ |
12 | Deserialize, DeserializeSeed, Deserializer, Error, MapAccess, SeqAccess, Unexpected, |
13 | Visitor, |
14 | }, |
15 | ser::{ |
16 | Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeTupleStruct, Serializer, |
17 | }, |
18 | }; |
19 | use static_assertions::assert_impl_all; |
20 | |
21 | use crate::{ |
22 | array_display_fmt, dict_display_fmt, signature_parser::SignatureParser, structure_display_fmt, |
23 | utils::*, Array, Basic, Dict, DynamicType, ObjectPath, OwnedValue, Signature, Str, Structure, |
24 | StructureBuilder, Type, |
25 | }; |
26 | #[cfg (feature = "gvariant" )] |
27 | use crate::{maybe_display_fmt, Maybe}; |
28 | |
29 | #[cfg (unix)] |
30 | use crate::Fd; |
31 | |
32 | /// A generic container, in the form of an enum that holds exactly one value of any of the other |
33 | /// types. |
34 | /// |
35 | /// Note that this type corresponds to the `VARIANT` data type defined by the [D-Bus specification] |
36 | /// and as such, its encoding is not the same as that of the enclosed value. |
37 | /// |
38 | /// # Examples |
39 | /// |
40 | /// ``` |
41 | /// use zvariant::{to_bytes, serialized::Context, Value, LE}; |
42 | /// |
43 | /// // Create a Value from an i16 |
44 | /// let v = Value::new(i16::max_value()); |
45 | /// |
46 | /// // Encode it |
47 | /// let ctxt = Context::new_dbus(LE, 0); |
48 | /// let encoding = to_bytes(ctxt, &v).unwrap(); |
49 | /// |
50 | /// // Decode it back |
51 | /// let v: Value = encoding.deserialize().unwrap().0; |
52 | /// |
53 | /// // Check everything is as expected |
54 | /// assert_eq!(i16::try_from(&v).unwrap(), i16::max_value()); |
55 | /// ``` |
56 | /// |
57 | /// Now let's try a more complicated example: |
58 | /// |
59 | /// ``` |
60 | /// use zvariant::{to_bytes, serialized::Context, LE}; |
61 | /// use zvariant::{Structure, Value, Str}; |
62 | /// |
63 | /// // Create a Value from a tuple this time |
64 | /// let v = Value::new((i16::max_value(), "hello" , true)); |
65 | /// |
66 | /// // Same drill as previous example |
67 | /// let ctxt = Context::new_dbus(LE, 0); |
68 | /// let encoding = to_bytes(ctxt, &v).unwrap(); |
69 | /// let v: Value = encoding.deserialize().unwrap().0; |
70 | /// |
71 | /// // Check everything is as expected |
72 | /// let s = Structure::try_from(v).unwrap(); |
73 | /// assert_eq!( |
74 | /// <(i16, Str, bool)>::try_from(s).unwrap(), |
75 | /// (i16::max_value(), Str::from("hello" ), true), |
76 | /// ); |
77 | /// ``` |
78 | /// |
79 | /// [D-Bus specification]: https://dbus.freedesktop.org/doc/dbus-specification.html#container-types |
80 | #[derive (Debug, PartialEq, PartialOrd)] |
81 | pub enum Value<'a> { |
82 | // Simple types |
83 | U8(u8), |
84 | Bool(bool), |
85 | I16(i16), |
86 | U16(u16), |
87 | I32(i32), |
88 | U32(u32), |
89 | I64(i64), |
90 | U64(u64), |
91 | F64(f64), |
92 | Str(Str<'a>), |
93 | Signature(Signature<'a>), |
94 | ObjectPath(ObjectPath<'a>), |
95 | Value(Box<Value<'a>>), |
96 | |
97 | // Container types |
98 | Array(Array<'a>), |
99 | Dict(Dict<'a, 'a>), |
100 | Structure(Structure<'a>), |
101 | #[cfg (feature = "gvariant" )] |
102 | Maybe(Maybe<'a>), |
103 | |
104 | #[cfg (unix)] |
105 | Fd(Fd<'a>), |
106 | } |
107 | |
108 | impl Hash for Value<'_> { |
109 | fn hash<H: Hasher>(&self, state: &mut H) { |
110 | discriminant(self).hash(state); |
111 | match self { |
112 | Self::U8(inner) => inner.hash(state), |
113 | Self::Bool(inner) => inner.hash(state), |
114 | Self::I16(inner) => inner.hash(state), |
115 | Self::U16(inner) => inner.hash(state), |
116 | Self::I32(inner) => inner.hash(state), |
117 | Self::U32(inner) => inner.hash(state), |
118 | Self::I64(inner) => inner.hash(state), |
119 | Self::U64(inner) => inner.hash(state), |
120 | // To hold the +0.0 == -0.0 => hash(+0.0) == hash(-0.0) property. |
121 | // See https://doc.rust-lang.org/beta/std/hash/trait.Hash.html#hash-and-eq |
122 | Self::F64(inner) if *inner == 0. => 0f64.to_le_bytes().hash(state), |
123 | Self::F64(inner) => inner.to_le_bytes().hash(state), |
124 | Self::Str(inner) => inner.hash(state), |
125 | Self::Signature(inner) => inner.hash(state), |
126 | Self::ObjectPath(inner) => inner.hash(state), |
127 | Self::Value(inner) => inner.hash(state), |
128 | Self::Array(inner) => inner.hash(state), |
129 | Self::Dict(inner) => inner.hash(state), |
130 | Self::Structure(inner) => inner.hash(state), |
131 | #[cfg (feature = "gvariant" )] |
132 | Self::Maybe(inner) => inner.hash(state), |
133 | #[cfg (unix)] |
134 | Self::Fd(inner) => inner.hash(state), |
135 | } |
136 | } |
137 | } |
138 | |
139 | impl Eq for Value<'_> {} |
140 | |
141 | impl Ord for Value<'_> { |
142 | fn cmp(&self, other: &Self) -> Ordering { |
143 | self.partial_cmp(other) |
144 | .unwrap_or_else(|| match (self, other) { |
145 | (Self::F64(lhs: &f64), Self::F64(rhs: &f64)) => lhs.total_cmp(rhs), |
146 | // `partial_cmp` returns `Some(_)` if either the discriminants are different |
147 | // or if both the left hand side and right hand side is `Self::F64(_)`, |
148 | // because `f64` is the only type in this enum, that does not implement `Ord`. |
149 | // This `match`-arm is therefore unreachable. |
150 | _ => unreachable!(), |
151 | }) |
152 | } |
153 | } |
154 | |
155 | assert_impl_all!(Value<'_>: Send, Sync, Unpin); |
156 | |
157 | macro_rules! serialize_value { |
158 | ($self:ident $serializer:ident.$method:ident $($first_arg:expr)*) => { |
159 | match $self { |
160 | Value::U8(value) => $serializer.$method($($first_arg,)* value), |
161 | Value::Bool(value) => $serializer.$method($($first_arg,)* value), |
162 | Value::I16(value) => $serializer.$method($($first_arg,)* value), |
163 | Value::U16(value) => $serializer.$method($($first_arg,)* value), |
164 | Value::I32(value) => $serializer.$method($($first_arg,)* value), |
165 | Value::U32(value) => $serializer.$method($($first_arg,)* value), |
166 | Value::I64(value) => $serializer.$method($($first_arg,)* value), |
167 | Value::U64(value) => $serializer.$method($($first_arg,)* value), |
168 | Value::F64(value) => $serializer.$method($($first_arg,)* value), |
169 | Value::Str(value) => $serializer.$method($($first_arg,)* value), |
170 | Value::Signature(value) => $serializer.$method($($first_arg,)* value), |
171 | Value::ObjectPath(value) => $serializer.$method($($first_arg,)* value), |
172 | Value::Value(value) => $serializer.$method($($first_arg,)* value), |
173 | |
174 | // Container types |
175 | Value::Array(value) => $serializer.$method($($first_arg,)* value), |
176 | Value::Dict(value) => $serializer.$method($($first_arg,)* value), |
177 | Value::Structure(value) => $serializer.$method($($first_arg,)* value), |
178 | #[cfg(feature = "gvariant" )] |
179 | Value::Maybe(value) => $serializer.$method($($first_arg,)* value), |
180 | |
181 | #[cfg(unix)] |
182 | Value::Fd(value) => $serializer.$method($($first_arg,)* value), |
183 | } |
184 | } |
185 | } |
186 | |
187 | impl<'a> Value<'a> { |
188 | /// Make a [`Value`] for a given value. |
189 | /// |
190 | /// In general, you can use [`Into`] trait on basic types, except |
191 | /// when you explicitly need to wrap [`Value`] itself, in which |
192 | /// case this constructor comes handy. |
193 | /// |
194 | /// # Examples |
195 | /// |
196 | /// ``` |
197 | /// use zvariant::Value; |
198 | /// |
199 | /// let s = Value::new("hello" ); |
200 | /// let u: Value = 51.into(); |
201 | /// assert_ne!(s, u); |
202 | /// ``` |
203 | /// |
204 | /// [`Value`]: enum.Value.html |
205 | /// [`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html |
206 | pub fn new<T>(value: T) -> Self |
207 | where |
208 | T: Into<Self> + DynamicType, |
209 | { |
210 | // With specialization, we wouldn't have this |
211 | if value.dynamic_signature() == VARIANT_SIGNATURE_STR { |
212 | Self::Value(Box::new(value.into())) |
213 | } else { |
214 | value.into() |
215 | } |
216 | } |
217 | |
218 | /// Try to create an owned version of `self`. |
219 | /// |
220 | /// # Errors |
221 | /// |
222 | /// This method can currently only fail on Unix platforms for [`Value::Fd`] variant. This |
223 | /// happens when the current process exceeds the maximum number of open file descriptors. |
224 | pub fn try_to_owned(&self) -> crate::Result<OwnedValue> { |
225 | Ok(OwnedValue(match self { |
226 | Value::U8(v) => Value::U8(*v), |
227 | Value::Bool(v) => Value::Bool(*v), |
228 | Value::I16(v) => Value::I16(*v), |
229 | Value::U16(v) => Value::U16(*v), |
230 | Value::I32(v) => Value::I32(*v), |
231 | Value::U32(v) => Value::U32(*v), |
232 | Value::I64(v) => Value::I64(*v), |
233 | Value::U64(v) => Value::U64(*v), |
234 | Value::F64(v) => Value::F64(*v), |
235 | Value::Str(v) => Value::Str(v.to_owned()), |
236 | Value::Signature(v) => Value::Signature(v.to_owned()), |
237 | Value::ObjectPath(v) => Value::ObjectPath(v.to_owned()), |
238 | Value::Value(v) => { |
239 | let o = OwnedValue::try_from(&**v)?; |
240 | Value::Value(Box::new(o.into_inner())) |
241 | } |
242 | |
243 | Value::Array(v) => Value::Array(v.try_to_owned()?), |
244 | Value::Dict(v) => Value::Dict(v.try_to_owned()?), |
245 | Value::Structure(v) => Value::Structure(v.try_to_owned()?), |
246 | #[cfg (feature = "gvariant" )] |
247 | Value::Maybe(v) => Value::Maybe(v.try_to_owned()?), |
248 | #[cfg (unix)] |
249 | Value::Fd(v) => Value::Fd(v.try_to_owned()?), |
250 | })) |
251 | } |
252 | |
253 | /// Get the signature of the enclosed value. |
254 | pub fn value_signature(&self) -> Signature<'_> { |
255 | match self { |
256 | Value::U8(_) => u8::signature(), |
257 | Value::Bool(_) => bool::signature(), |
258 | Value::I16(_) => i16::signature(), |
259 | Value::U16(_) => u16::signature(), |
260 | Value::I32(_) => i32::signature(), |
261 | Value::U32(_) => u32::signature(), |
262 | Value::I64(_) => i64::signature(), |
263 | Value::U64(_) => u64::signature(), |
264 | Value::F64(_) => f64::signature(), |
265 | Value::Str(_) => <&str>::signature(), |
266 | Value::Signature(_) => Signature::signature(), |
267 | Value::ObjectPath(_) => ObjectPath::signature(), |
268 | Value::Value(_) => Signature::from_static_str_unchecked("v" ), |
269 | |
270 | // Container types |
271 | Value::Array(value) => value.full_signature().as_ref(), |
272 | Value::Dict(value) => value.full_signature().as_ref(), |
273 | Value::Structure(value) => value.full_signature().as_ref(), |
274 | #[cfg (feature = "gvariant" )] |
275 | Value::Maybe(value) => value.full_signature().as_ref(), |
276 | |
277 | #[cfg (unix)] |
278 | Value::Fd(_) => Fd::signature(), |
279 | } |
280 | } |
281 | |
282 | /// Try to clone the value. |
283 | /// |
284 | /// # Errors |
285 | /// |
286 | /// This method can currently only fail on Unix platforms for [`Value::Fd`] variant containing |
287 | /// an [`Fd::Owned`] variant. This happens when the current process exceeds the maximum number |
288 | /// of open file descriptors. |
289 | pub fn try_clone(&self) -> crate::Result<Self> { |
290 | Ok(match self { |
291 | Value::U8(v) => Value::U8(*v), |
292 | Value::Bool(v) => Value::Bool(*v), |
293 | Value::I16(v) => Value::I16(*v), |
294 | Value::U16(v) => Value::U16(*v), |
295 | Value::I32(v) => Value::I32(*v), |
296 | Value::U32(v) => Value::U32(*v), |
297 | Value::I64(v) => Value::I64(*v), |
298 | Value::U64(v) => Value::U64(*v), |
299 | Value::F64(v) => Value::F64(*v), |
300 | Value::Str(v) => Value::Str(v.clone()), |
301 | Value::Signature(v) => Value::Signature(v.clone()), |
302 | Value::ObjectPath(v) => Value::ObjectPath(v.clone()), |
303 | Value::Value(v) => Value::Value(Box::new(v.try_clone()?)), |
304 | Value::Array(v) => Value::Array(v.try_clone()?), |
305 | Value::Dict(v) => Value::Dict(v.try_clone()?), |
306 | Value::Structure(v) => Value::Structure(v.try_clone()?), |
307 | #[cfg (feature = "gvariant" )] |
308 | Value::Maybe(v) => Value::Maybe(v.try_clone()?), |
309 | #[cfg (unix)] |
310 | Value::Fd(v) => Value::Fd(v.try_clone()?), |
311 | }) |
312 | } |
313 | |
314 | pub(crate) fn serialize_value_as_struct_field<S>( |
315 | &self, |
316 | name: &'static str, |
317 | serializer: &mut S, |
318 | ) -> Result<(), S::Error> |
319 | where |
320 | S: SerializeStruct, |
321 | { |
322 | serialize_value!(self serializer.serialize_field name) |
323 | } |
324 | |
325 | pub(crate) fn serialize_value_as_tuple_struct_field<S>( |
326 | &self, |
327 | serializer: &mut S, |
328 | ) -> Result<(), S::Error> |
329 | where |
330 | S: SerializeTupleStruct, |
331 | { |
332 | serialize_value!(self serializer.serialize_field) |
333 | } |
334 | |
335 | // Really crappy that we need to do this separately for struct and seq cases. :( |
336 | pub(crate) fn serialize_value_as_seq_element<S>( |
337 | &self, |
338 | serializer: &mut S, |
339 | ) -> Result<(), S::Error> |
340 | where |
341 | S: SerializeSeq, |
342 | { |
343 | serialize_value!(self serializer.serialize_element) |
344 | } |
345 | |
346 | pub(crate) fn serialize_value_as_dict_key<S>(&self, serializer: &mut S) -> Result<(), S::Error> |
347 | where |
348 | S: SerializeMap, |
349 | { |
350 | serialize_value!(self serializer.serialize_key) |
351 | } |
352 | |
353 | pub(crate) fn serialize_value_as_dict_value<S>( |
354 | &self, |
355 | serializer: &mut S, |
356 | ) -> Result<(), S::Error> |
357 | where |
358 | S: SerializeMap, |
359 | { |
360 | serialize_value!(self serializer.serialize_value) |
361 | } |
362 | |
363 | #[cfg (feature = "gvariant" )] |
364 | pub(crate) fn serialize_value_as_some<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
365 | where |
366 | S: Serializer, |
367 | { |
368 | serialize_value!(self serializer.serialize_some) |
369 | } |
370 | |
371 | /// Try to get the underlying type `T`. |
372 | /// |
373 | /// Note that [`TryFrom<Value>`] is implemented for various types, and it's usually best to use |
374 | /// that instead. However, in generic code where you also want to unwrap [`Value::Value`], |
375 | /// you should use this function (because [`TryFrom<Value>`] can not be implemented for `Value` |
376 | /// itself as [`From<Value>`] is implicitly implemented for `Value`). |
377 | /// |
378 | /// # Examples |
379 | /// |
380 | /// ``` |
381 | /// use zvariant::{Error, Result, Value}; |
382 | /// |
383 | /// fn value_vec_to_type_vec<'a, T>(values: Vec<Value<'a>>) -> Result<Vec<T>> |
384 | /// where |
385 | /// T: TryFrom<Value<'a>>, |
386 | /// <T as TryFrom<Value<'a>>>::Error: Into<Error>, |
387 | /// { |
388 | /// let mut res = vec![]; |
389 | /// for value in values.into_iter() { |
390 | /// res.push(value.downcast()?); |
391 | /// } |
392 | /// |
393 | /// Ok(res) |
394 | /// } |
395 | /// |
396 | /// // Let's try u32 values first |
397 | /// let v = vec![Value::U32(42), Value::U32(43)]; |
398 | /// let v = value_vec_to_type_vec::<u32>(v).unwrap(); |
399 | /// assert_eq!(v[0], 42); |
400 | /// assert_eq!(v[1], 43); |
401 | /// |
402 | /// // Now try Value values |
403 | /// let v = vec![Value::new(Value::U32(42)), Value::new(Value::U32(43))]; |
404 | /// let v = value_vec_to_type_vec::<Value>(v).unwrap(); |
405 | /// assert_eq!(v[0], Value::U32(42)); |
406 | /// assert_eq!(v[1], Value::U32(43)); |
407 | /// ``` |
408 | /// |
409 | /// [`Value::Value`]: enum.Value.html#variant.Value |
410 | /// [`TryFrom<Value>`]: https://doc.rust-lang.org/std/convert/trait.TryFrom.html |
411 | /// [`From<Value>`]: https://doc.rust-lang.org/std/convert/trait.From.html |
412 | pub fn downcast<T>(self) -> Result<T, crate::Error> |
413 | where |
414 | T: ?Sized + TryFrom<Value<'a>>, |
415 | <T as TryFrom<Value<'a>>>::Error: Into<crate::Error>, |
416 | { |
417 | if let Value::Value(v) = self { |
418 | T::try_from(*v) |
419 | } else { |
420 | T::try_from(self) |
421 | } |
422 | .map_err(Into::into) |
423 | } |
424 | |
425 | /// Try to get the underlying type `T`. |
426 | /// |
427 | /// Same as [`downcast`] except it doesn't consume `self` and hence requires |
428 | /// `T: TryFrom<&Value<_>>`. |
429 | /// |
430 | /// # Examples |
431 | /// |
432 | /// ``` |
433 | /// use zvariant::{Error, Result, Value}; |
434 | /// |
435 | /// fn value_vec_to_type_vec<'a, T>(values: &'a Vec<Value<'a>>) -> Result<Vec<&'a T>> |
436 | /// where |
437 | /// &'a T: TryFrom<&'a Value<'a>>, |
438 | /// <&'a T as TryFrom<&'a Value<'a>>>::Error: Into<Error>, |
439 | /// { |
440 | /// let mut res = vec![]; |
441 | /// for value in values.into_iter() { |
442 | /// res.push(value.downcast_ref()?); |
443 | /// } |
444 | /// |
445 | /// Ok(res) |
446 | /// } |
447 | /// |
448 | /// // Let's try u32 values first |
449 | /// let v = vec![Value::U32(42), Value::U32(43)]; |
450 | /// let v = value_vec_to_type_vec::<u32>(&v).unwrap(); |
451 | /// assert_eq!(*v[0], 42); |
452 | /// assert_eq!(*v[1], 43); |
453 | /// |
454 | /// // Now try Value values |
455 | /// let v = vec![Value::new(Value::U32(42)), Value::new(Value::U32(43))]; |
456 | /// let v = value_vec_to_type_vec::<Value>(&v).unwrap(); |
457 | /// assert_eq!(*v[0], Value::U32(42)); |
458 | /// assert_eq!(*v[1], Value::U32(43)); |
459 | /// ``` |
460 | /// |
461 | /// [`downcast`]: enum.Value.html#method.downcast |
462 | pub fn downcast_ref<T>(&'a self) -> Result<T, crate::Error> |
463 | where |
464 | T: ?Sized + TryFrom<&'a Value<'a>>, |
465 | <T as TryFrom<&'a Value<'a>>>::Error: Into<crate::Error>, |
466 | { |
467 | if let Value::Value(v) = self { |
468 | <T>::try_from(v) |
469 | } else { |
470 | <T>::try_from(self) |
471 | } |
472 | .map_err(Into::into) |
473 | } |
474 | } |
475 | |
476 | impl Display for Value<'_> { |
477 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
478 | value_display_fmt(self, f, type_annotate:true) |
479 | } |
480 | } |
481 | |
482 | /// Implemented based on https://gitlab.gnome.org/GNOME/glib/-/blob/e1d47f0b0d0893ac9171e24cc7bf635495376546/glib/gvariant.c#L2213 |
483 | pub(crate) fn value_display_fmt( |
484 | value: &Value<'_>, |
485 | f: &mut std::fmt::Formatter<'_>, |
486 | type_annotate: bool, |
487 | ) -> std::fmt::Result { |
488 | match value { |
489 | Value::U8(num) => { |
490 | if type_annotate { |
491 | f.write_str("byte " )?; |
492 | } |
493 | write!(f, "0x {:02x}" , num) |
494 | } |
495 | Value::Bool(boolean) => { |
496 | write!(f, " {}" , boolean) |
497 | } |
498 | Value::I16(num) => { |
499 | if type_annotate { |
500 | f.write_str("int16 " )?; |
501 | } |
502 | write!(f, " {}" , num) |
503 | } |
504 | Value::U16(num) => { |
505 | if type_annotate { |
506 | f.write_str("uint16 " )?; |
507 | } |
508 | write!(f, " {}" , num) |
509 | } |
510 | Value::I32(num) => { |
511 | // Never annotate this type because it is the default for numbers |
512 | write!(f, " {}" , num) |
513 | } |
514 | Value::U32(num) => { |
515 | if type_annotate { |
516 | f.write_str("uint32 " )?; |
517 | } |
518 | write!(f, " {}" , num) |
519 | } |
520 | Value::I64(num) => { |
521 | if type_annotate { |
522 | f.write_str("int64 " )?; |
523 | } |
524 | write!(f, " {}" , num) |
525 | } |
526 | Value::U64(num) => { |
527 | if type_annotate { |
528 | f.write_str("uint64 " )?; |
529 | } |
530 | write!(f, " {}" , num) |
531 | } |
532 | Value::F64(num) => { |
533 | if num.fract() == 0. { |
534 | // Add a dot to make it clear that this is a float |
535 | write!(f, " {}." , num) |
536 | } else { |
537 | write!(f, " {}" , num) |
538 | } |
539 | } |
540 | Value::Str(string) => { |
541 | write!(f, " {:?}" , string.as_str()) |
542 | } |
543 | Value::Signature(val) => { |
544 | if type_annotate { |
545 | f.write_str("signature " )?; |
546 | } |
547 | write!(f, " {:?}" , val.as_str()) |
548 | } |
549 | Value::ObjectPath(val) => { |
550 | if type_annotate { |
551 | f.write_str("objectpath " )?; |
552 | } |
553 | write!(f, " {:?}" , val.as_str()) |
554 | } |
555 | Value::Value(child) => { |
556 | f.write_char('<' )?; |
557 | |
558 | // Always annotate types in nested variants, because they are (by nature) of |
559 | // variable type. |
560 | value_display_fmt(child, f, true)?; |
561 | |
562 | f.write_char('>' )?; |
563 | Ok(()) |
564 | } |
565 | Value::Array(array) => array_display_fmt(array, f, type_annotate), |
566 | Value::Dict(dict) => dict_display_fmt(dict, f, type_annotate), |
567 | Value::Structure(structure) => structure_display_fmt(structure, f, type_annotate), |
568 | #[cfg (feature = "gvariant" )] |
569 | Value::Maybe(maybe) => maybe_display_fmt(maybe, f, type_annotate), |
570 | #[cfg (unix)] |
571 | Value::Fd(handle) => { |
572 | if type_annotate { |
573 | f.write_str("handle " )?; |
574 | } |
575 | write!(f, " {}" , handle) |
576 | } |
577 | } |
578 | } |
579 | |
580 | impl<'a> Serialize for Value<'a> { |
581 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
582 | where |
583 | S: Serializer, |
584 | { |
585 | // Serializer implementation needs to ensure padding isn't added for Value. |
586 | let mut structure: ::SerializeStruct = serializer.serialize_struct(name:"zvariant::Value" , len:2)?; |
587 | |
588 | let signature: Signature<'_> = self.value_signature(); |
589 | structure.serialize_field(key:"zvariant::Value::Signature" , &signature)?; |
590 | |
591 | self.serialize_value_as_struct_field(name:"zvariant::Value::Value" , &mut structure)?; |
592 | |
593 | structure.end() |
594 | } |
595 | } |
596 | |
597 | impl<'de: 'a, 'a> Deserialize<'de> for Value<'a> { |
598 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
599 | where |
600 | D: Deserializer<'de>, |
601 | { |
602 | let visitor: ValueVisitor = ValueVisitor; |
603 | |
604 | deserializer.deserialize_any(visitor) |
605 | } |
606 | } |
607 | |
608 | // Note that the Visitor implementations don't check for validity of the |
609 | // signature. That's left to the Deserialize implementation of Signature |
610 | // itself. |
611 | |
612 | struct ValueVisitor; |
613 | |
614 | impl<'de> Visitor<'de> for ValueVisitor { |
615 | type Value = Value<'de>; |
616 | |
617 | fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
618 | formatter.write_str("a Value" ) |
619 | } |
620 | |
621 | fn visit_seq<V>(self, mut visitor: V) -> Result<Value<'de>, V::Error> |
622 | where |
623 | V: SeqAccess<'de>, |
624 | { |
625 | let signature = visitor.next_element::<Signature<'_>>()?.ok_or_else(|| { |
626 | Error::invalid_value(Unexpected::Other("nothing" ), &"a Value signature" ) |
627 | })?; |
628 | let seed = ValueSeed::<Value<'_>> { |
629 | signature, |
630 | phantom: PhantomData, |
631 | }; |
632 | |
633 | visitor |
634 | .next_element_seed(seed)? |
635 | .ok_or_else(|| Error::invalid_value(Unexpected::Other("nothing" ), &"a Value value" )) |
636 | } |
637 | |
638 | fn visit_map<V>(self, mut visitor: V) -> Result<Value<'de>, V::Error> |
639 | where |
640 | V: MapAccess<'de>, |
641 | { |
642 | let (_, signature) = visitor |
643 | .next_entry::<&str, Signature<'_>>()? |
644 | .ok_or_else(|| { |
645 | Error::invalid_value(Unexpected::Other("nothing" ), &"a Value signature" ) |
646 | })?; |
647 | let _ = visitor.next_key::<&str>()?; |
648 | |
649 | let seed = ValueSeed::<Value<'_>> { |
650 | signature, |
651 | phantom: PhantomData, |
652 | }; |
653 | visitor.next_value_seed(seed) |
654 | } |
655 | } |
656 | |
657 | pub(crate) struct SignatureSeed<'de> { |
658 | pub signature: Signature<'de>, |
659 | } |
660 | |
661 | impl<'de> SignatureSeed<'de> { |
662 | pub(crate) fn visit_array<V>(self, mut visitor: V) -> Result<Array<'de>, V::Error> |
663 | where |
664 | V: SeqAccess<'de>, |
665 | { |
666 | let element_signature = self.signature.slice(1..); |
667 | let mut array = Array::new_full_signature(self.signature.clone()); |
668 | |
669 | while let Some(elem) = visitor.next_element_seed(ValueSeed::<Value<'_>> { |
670 | signature: element_signature.clone(), |
671 | phantom: PhantomData, |
672 | })? { |
673 | elem.value_signature(); |
674 | array.append(elem).map_err(Error::custom)?; |
675 | } |
676 | |
677 | Ok(array) |
678 | } |
679 | |
680 | pub(crate) fn visit_struct<V>(self, mut visitor: V) -> Result<Structure<'de>, V::Error> |
681 | where |
682 | V: SeqAccess<'de>, |
683 | { |
684 | let mut i = 1; |
685 | let signature_end = self.signature.len() - 1; |
686 | let mut builder = StructureBuilder::new(); |
687 | while i < signature_end { |
688 | let fields_signature = self.signature.slice(i..signature_end); |
689 | let parser = SignatureParser::new(fields_signature.as_ref()); |
690 | let len = parser.next_signature().map_err(Error::custom)?.len(); |
691 | let field_signature = fields_signature.slice(0..len); |
692 | i += field_signature.len(); |
693 | |
694 | if let Some(field) = visitor.next_element_seed(ValueSeed::<Value<'_>> { |
695 | signature: field_signature, |
696 | phantom: PhantomData, |
697 | })? { |
698 | builder = builder.append_field(field); |
699 | } |
700 | } |
701 | Ok(builder.build_with_signature(self.signature)) |
702 | } |
703 | } |
704 | |
705 | impl<'de, T> From<ValueSeed<'de, T>> for SignatureSeed<'de> { |
706 | fn from(seed: ValueSeed<'de, T>) -> Self { |
707 | SignatureSeed { |
708 | signature: seed.signature, |
709 | } |
710 | } |
711 | } |
712 | |
713 | struct ValueSeed<'de, T> { |
714 | signature: Signature<'de>, |
715 | phantom: PhantomData<T>, |
716 | } |
717 | |
718 | impl<'de, T> ValueSeed<'de, T> |
719 | where |
720 | T: Deserialize<'de>, |
721 | { |
722 | #[inline ] |
723 | fn visit_array<V>(self, visitor: V) -> Result<Value<'de>, V::Error> |
724 | where |
725 | V: SeqAccess<'de>, |
726 | { |
727 | SignatureSeed::from(self) |
728 | .visit_array(visitor) |
729 | .map(Value::Array) |
730 | } |
731 | |
732 | #[inline ] |
733 | fn visit_struct<V>(self, visitor: V) -> Result<Value<'de>, V::Error> |
734 | where |
735 | V: SeqAccess<'de>, |
736 | { |
737 | SignatureSeed::from(self) |
738 | .visit_struct(visitor) |
739 | .map(Value::Structure) |
740 | } |
741 | |
742 | #[inline ] |
743 | fn visit_variant<V>(self, visitor: V) -> Result<Value<'de>, V::Error> |
744 | where |
745 | V: SeqAccess<'de>, |
746 | { |
747 | ValueVisitor |
748 | .visit_seq(visitor) |
749 | .map(|v| Value::Value(Box::new(v))) |
750 | } |
751 | } |
752 | |
753 | macro_rules! value_seed_basic_method { |
754 | ($name:ident, $type:ty) => { |
755 | #[inline] |
756 | fn $name<E>(self, value: $type) -> Result<Value<'de>, E> |
757 | where |
758 | E: serde::de::Error, |
759 | { |
760 | Ok(value.into()) |
761 | } |
762 | }; |
763 | } |
764 | |
765 | macro_rules! value_seed_str_method { |
766 | ($name:ident, $type:ty, $constructor:ident) => { |
767 | fn $name<E>(self, value: $type) -> Result<Value<'de>, E> |
768 | where |
769 | E: serde::de::Error, |
770 | { |
771 | match self.signature.as_str() { |
772 | <&str>::SIGNATURE_STR => Ok(Value::Str(Str::from(value))), |
773 | Signature::SIGNATURE_STR => Ok(Value::Signature(Signature::$constructor(value))), |
774 | ObjectPath::SIGNATURE_STR => Ok(Value::ObjectPath(ObjectPath::$constructor(value))), |
775 | _ => { |
776 | let expected = format!( |
777 | "`{}`, `{}` or `{}`" , |
778 | <&str>::SIGNATURE_STR, |
779 | Signature::SIGNATURE_STR, |
780 | ObjectPath::SIGNATURE_STR, |
781 | ); |
782 | Err(Error::invalid_type( |
783 | Unexpected::Str(self.signature.as_str()), |
784 | &expected.as_str(), |
785 | )) |
786 | } |
787 | } |
788 | } |
789 | }; |
790 | } |
791 | |
792 | impl<'de, T> Visitor<'de> for ValueSeed<'de, T> |
793 | where |
794 | T: Deserialize<'de>, |
795 | { |
796 | type Value = Value<'de>; |
797 | |
798 | fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
799 | formatter.write_str("a Value value" ) |
800 | } |
801 | |
802 | value_seed_basic_method!(visit_bool, bool); |
803 | value_seed_basic_method!(visit_i16, i16); |
804 | value_seed_basic_method!(visit_i64, i64); |
805 | value_seed_basic_method!(visit_u8, u8); |
806 | value_seed_basic_method!(visit_u16, u16); |
807 | value_seed_basic_method!(visit_u32, u32); |
808 | value_seed_basic_method!(visit_u64, u64); |
809 | value_seed_basic_method!(visit_f64, f64); |
810 | |
811 | fn visit_i32<E>(self, value: i32) -> Result<Value<'de>, E> |
812 | where |
813 | E: serde::de::Error, |
814 | { |
815 | let v = match self.signature.as_bytes().first().ok_or_else(|| { |
816 | Error::invalid_value( |
817 | Unexpected::Other("nothing" ), |
818 | &"i32 or fd signature character" , |
819 | ) |
820 | })? { |
821 | #[cfg (unix)] |
822 | b'h' => { |
823 | // SAFETY: The `'de` lifetimes will ensure the borrow won't outlive the raw FD. |
824 | let fd = unsafe { std::os::fd::BorrowedFd::borrow_raw(value) }; |
825 | Fd::Borrowed(fd).into() |
826 | } |
827 | _ => value.into(), |
828 | }; |
829 | |
830 | Ok(v) |
831 | } |
832 | |
833 | #[inline ] |
834 | fn visit_str<E>(self, value: &str) -> Result<Value<'de>, E> |
835 | where |
836 | E: serde::de::Error, |
837 | { |
838 | self.visit_string(String::from(value)) |
839 | } |
840 | |
841 | value_seed_str_method!(visit_borrowed_str, &'de str, from_str_unchecked); |
842 | |
843 | fn visit_seq<V>(self, visitor: V) -> Result<Value<'de>, V::Error> |
844 | where |
845 | V: SeqAccess<'de>, |
846 | { |
847 | match self.signature.as_bytes().first().ok_or_else(|| { |
848 | Error::invalid_value( |
849 | Unexpected::Other("nothing" ), |
850 | &"Array or Struct signature character" , |
851 | ) |
852 | })? { |
853 | // For some reason rustc doesn't like us using ARRAY_SIGNATURE_CHAR const |
854 | b'a' => self.visit_array(visitor), |
855 | b'(' => self.visit_struct(visitor), |
856 | b'v' => self.visit_variant(visitor), |
857 | b => Err(Error::invalid_value( |
858 | Unexpected::Char(*b as char), |
859 | &"a Value signature" , |
860 | )), |
861 | } |
862 | } |
863 | |
864 | fn visit_map<V>(self, mut visitor: V) -> Result<Value<'de>, V::Error> |
865 | where |
866 | V: MapAccess<'de>, |
867 | { |
868 | if self.signature.len() < 5 { |
869 | return Err(serde::de::Error::invalid_length( |
870 | self.signature.len(), |
871 | &">= 5 characters in dict entry signature" , |
872 | )); |
873 | } |
874 | let key_signature = self.signature.slice(2..3); |
875 | let signature_end = self.signature.len() - 1; |
876 | let value_signature = self.signature.slice(3..signature_end); |
877 | let mut dict = Dict::new_full_signature(self.signature.clone()); |
878 | |
879 | while let Some((key, value)) = visitor.next_entry_seed( |
880 | ValueSeed::<Value<'_>> { |
881 | signature: key_signature.clone(), |
882 | phantom: PhantomData, |
883 | }, |
884 | ValueSeed::<Value<'_>> { |
885 | signature: value_signature.clone(), |
886 | phantom: PhantomData, |
887 | }, |
888 | )? { |
889 | dict.append(key, value).map_err(Error::custom)?; |
890 | } |
891 | |
892 | Ok(Value::Dict(dict)) |
893 | } |
894 | |
895 | #[cfg (feature = "gvariant" )] |
896 | fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> |
897 | where |
898 | D: Deserializer<'de>, |
899 | { |
900 | let visitor = ValueSeed::<T> { |
901 | signature: self.signature.slice(1..), |
902 | phantom: PhantomData, |
903 | }; |
904 | |
905 | deserializer |
906 | .deserialize_any(visitor) |
907 | .map(|v| Value::Maybe(Maybe::just_full_signature(v, self.signature))) |
908 | } |
909 | |
910 | #[cfg (not(feature = "gvariant" ))] |
911 | fn visit_some<D>(self, _deserializer: D) -> Result<Self::Value, D::Error> |
912 | where |
913 | D: Deserializer<'de>, |
914 | { |
915 | panic!("`Maybe` type is only supported for GVariant format but it's disabled" ); |
916 | } |
917 | |
918 | #[cfg (feature = "gvariant" )] |
919 | fn visit_none<E>(self) -> Result<Self::Value, E> |
920 | where |
921 | E: Error, |
922 | { |
923 | let value = Maybe::nothing_full_signature(self.signature); |
924 | |
925 | Ok(Value::Maybe(value)) |
926 | } |
927 | |
928 | #[cfg (not(feature = "gvariant" ))] |
929 | fn visit_none<E>(self) -> Result<Self::Value, E> |
930 | where |
931 | E: Error, |
932 | { |
933 | panic!("`Maybe` type is only supported for GVariant format but it's disabled" ); |
934 | } |
935 | } |
936 | |
937 | impl<'de, T> DeserializeSeed<'de> for ValueSeed<'de, T> |
938 | where |
939 | T: Deserialize<'de>, |
940 | { |
941 | type Value = Value<'de>; |
942 | |
943 | fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> |
944 | where |
945 | D: Deserializer<'de>, |
946 | { |
947 | deserializer.deserialize_any(self) |
948 | } |
949 | } |
950 | |
951 | impl<'a> Type for Value<'a> { |
952 | fn signature() -> Signature<'static> { |
953 | Signature::from_static_str_unchecked(VARIANT_SIGNATURE_STR) |
954 | } |
955 | } |
956 | |
957 | impl<'a> TryFrom<&Value<'a>> for Value<'a> { |
958 | type Error = crate::Error; |
959 | |
960 | fn try_from(value: &Value<'a>) -> crate::Result<Value<'a>> { |
961 | value.try_clone() |
962 | } |
963 | } |
964 | |
965 | #[cfg (test)] |
966 | mod tests { |
967 | use std::collections::HashMap; |
968 | |
969 | use super::*; |
970 | |
971 | #[test ] |
972 | fn value_display() { |
973 | assert_eq!( |
974 | Value::new(( |
975 | 255_u8, |
976 | true, |
977 | -1_i16, |
978 | 65535_u16, |
979 | -1, |
980 | 1_u32, |
981 | -9223372036854775808_i64, |
982 | 18446744073709551615_u64, |
983 | (-1., 1.0, 11000000000., 1.1e-10) |
984 | )) |
985 | .to_string(), |
986 | "(byte 0xff, true, int16 -1, uint16 65535, -1, uint32 1, \ |
987 | int64 -9223372036854775808, uint64 18446744073709551615, \ |
988 | (-1., 1., 11000000000., 0.00000000011))" |
989 | ); |
990 | |
991 | assert_eq!( |
992 | Value::new(vec![ |
993 | "" , " " , "a" , r#"""# , "'" , "a'b" , "a' \"b" , " \\" , " \n' \"" , |
994 | ]) |
995 | .to_string(), |
996 | r#"["", " ", "a", "\"", "'", "a'b", "a'\"b", "\\", "\n'\""]"# |
997 | ); |
998 | assert_eq!( |
999 | Value::new(vec![ |
1000 | " \x07\x08\x09\x0A\x0B\x0C\x0D" , |
1001 | " \x7F" , |
1002 | char::from_u32(0xD8000).unwrap().to_string().as_str() |
1003 | ]) |
1004 | .to_string(), |
1005 | r#"["\u{7}\u{8}\t\n\u{b}\u{c}\r", "\u{7f}", "\u{d8000}"]"# |
1006 | ); |
1007 | |
1008 | assert_eq!( |
1009 | Value::new(( |
1010 | vec![ |
1011 | Signature::from_static_str("" ).unwrap(), |
1012 | Signature::from_static_str("(ysa{sd})" ).unwrap(), |
1013 | ], |
1014 | vec![ |
1015 | ObjectPath::from_static_str("/" ).unwrap(), |
1016 | ObjectPath::from_static_str("/a/very/looooooooooooooooooooooooo0000o0ng/path" ) |
1017 | .unwrap(), |
1018 | ], |
1019 | vec![ |
1020 | Value::new(0_u8), |
1021 | Value::new((Value::new(51), Value::new(Value::new(1_u32)))), |
1022 | ] |
1023 | )) |
1024 | .to_string(), |
1025 | "([signature \"\", \"(ysa{sd}) \"], \ |
1026 | [objectpath \"/ \", \"/a/very/looooooooooooooooooooooooo0000o0ng/path \"], \ |
1027 | [<byte 0x00>, <(<51>, <<uint32 1>>)>])" |
1028 | ); |
1029 | |
1030 | assert_eq!(Value::new(vec![] as Vec<Vec<i64>>).to_string(), "@aax []" ); |
1031 | assert_eq!( |
1032 | Value::new(vec![ |
1033 | vec![0_i16, 1_i16], |
1034 | vec![2_i16, 3_i16], |
1035 | vec![4_i16, 5_i16] |
1036 | ]) |
1037 | .to_string(), |
1038 | "[[int16 0, 1], [2, 3], [4, 5]]" |
1039 | ); |
1040 | assert_eq!( |
1041 | Value::new(vec![ |
1042 | b"Hello" .to_vec(), |
1043 | b"Hell \0o" .to_vec(), |
1044 | b"H \0ello \0" .to_vec(), |
1045 | b"Hello \0" .to_vec(), |
1046 | b" \0" .to_vec(), |
1047 | b" \0" .to_vec(), |
1048 | b"' \0" .to_vec(), |
1049 | b" \n' \"\0" .to_vec(), |
1050 | b" \\\0" .to_vec(), |
1051 | ]) |
1052 | .to_string(), |
1053 | "[[byte 0x48, 0x65, 0x6c, 0x6c, 0x6f], \ |
1054 | [0x48, 0x65, 0x6c, 0x6c, 0x00, 0x6f], \ |
1055 | [0x48, 0x00, 0x65, 0x6c, 0x6c, 0x6f, 0x00], \ |
1056 | b \"Hello \", b \"\", b \" \", b \"' \", b \"\\n' \\\"\", b \"\\\\\"]" |
1057 | ); |
1058 | |
1059 | assert_eq!( |
1060 | Value::new(HashMap::<bool, bool>::new()).to_string(), |
1061 | "@a{bb} {}" |
1062 | ); |
1063 | assert_eq!( |
1064 | Value::new(vec![(true, 0_i64)].into_iter().collect::<HashMap<_, _>>()).to_string(), |
1065 | "{true: int64 0}" , |
1066 | ); |
1067 | // The order of the entries may vary |
1068 | let val = Value::new( |
1069 | vec![(32_u16, 64_i64), (100_u16, 200_i64)] |
1070 | .into_iter() |
1071 | .collect::<HashMap<_, _>>(), |
1072 | ) |
1073 | .to_string(); |
1074 | assert!(val.starts_with('{' )); |
1075 | assert!(val.ends_with('}' )); |
1076 | assert_eq!(val.matches("uint16" ).count(), 1); |
1077 | assert_eq!(val.matches("int64" ).count(), 1); |
1078 | |
1079 | let items_str = val.split(", " ).collect::<Vec<_>>(); |
1080 | assert_eq!(items_str.len(), 2); |
1081 | assert!(items_str |
1082 | .iter() |
1083 | .any(|str| str.contains("32" ) && str.contains(": " ) && str.contains("64" ))); |
1084 | assert!(items_str |
1085 | .iter() |
1086 | .any(|str| str.contains("100" ) && str.contains(": " ) && str.contains("200" ))); |
1087 | |
1088 | assert_eq!(Value::new(Structure::default()).to_string(), "()" ); |
1089 | assert_eq!( |
1090 | Value::new(((true,), (true, false), (true, true, false))).to_string(), |
1091 | "((true,), (true, false), (true, true, false))" |
1092 | ); |
1093 | |
1094 | #[cfg (any(feature = "gvariant" , feature = "option-as-array" ))] |
1095 | { |
1096 | #[cfg (unix)] |
1097 | use std::os::fd::BorrowedFd; |
1098 | |
1099 | #[cfg (all(feature = "gvariant" , not(feature = "option-as-array" )))] |
1100 | let s = "((@mn 0, @mmn 0, @mmmn 0), \ |
1101 | (@mn nothing, @mmn just nothing, @mmmn just just nothing), \ |
1102 | (@mmn nothing, @mmmn just nothing))" ; |
1103 | #[cfg (feature = "option-as-array" )] |
1104 | let s = "(([int16 0], [[int16 0]], [[[int16 0]]]), \ |
1105 | (@an [], [@an []], [[@an []]]), \ |
1106 | (@aan [], [@aan []]))" ; |
1107 | assert_eq!( |
1108 | Value::new(( |
1109 | (Some(0_i16), Some(Some(0_i16)), Some(Some(Some(0_i16))),), |
1110 | (None::<i16>, Some(None::<i16>), Some(Some(None::<i16>)),), |
1111 | (None::<Option<i16>>, Some(None::<Option<i16>>)), |
1112 | )) |
1113 | .to_string(), |
1114 | s, |
1115 | ); |
1116 | |
1117 | #[cfg (unix)] |
1118 | assert_eq!( |
1119 | Value::new(vec![ |
1120 | Fd::from(unsafe { BorrowedFd::borrow_raw(0) }), |
1121 | Fd::from(unsafe { BorrowedFd::borrow_raw(-100) }) |
1122 | ]) |
1123 | .to_string(), |
1124 | "[handle 0, -100]" |
1125 | ); |
1126 | |
1127 | #[cfg (all(feature = "gvariant" , not(feature = "option-as-array" )))] |
1128 | let s = "(@mb nothing, @mb nothing, \ |
1129 | @ma{sv} { \"size \": <(800, 600)>}, \ |
1130 | [<1>, <{ \"dimension \": <([2.4, 1.], \ |
1131 | @mmn 200, <(byte 0x03, \"Hello! \")>)>}>], \ |
1132 | 7777, objectpath \"/ \", 8888)" ; |
1133 | #[cfg (feature = "option-as-array" )] |
1134 | let s = "(@ab [], @ab [], [{ \"size \": <(800, 600)>}], \ |
1135 | [<1>, <{ \"dimension \": <([2.4, 1.], [[int16 200]], \ |
1136 | <(byte 0x03, \"Hello! \")>)>}>], 7777, objectpath \"/ \", 8888)" ; |
1137 | assert_eq!( |
1138 | Value::new(( |
1139 | None::<bool>, |
1140 | None::<bool>, |
1141 | Some( |
1142 | vec![("size" , Value::new((800, 600)))] |
1143 | .into_iter() |
1144 | .collect::<HashMap<_, _>>() |
1145 | ), |
1146 | vec![ |
1147 | Value::new(1), |
1148 | Value::new( |
1149 | vec![( |
1150 | "dimension" , |
1151 | Value::new(( |
1152 | vec![2.4, 1.], |
1153 | Some(Some(200_i16)), |
1154 | Value::new((3_u8, "Hello!" )) |
1155 | )) |
1156 | )] |
1157 | .into_iter() |
1158 | .collect::<HashMap<_, _>>() |
1159 | ) |
1160 | ], |
1161 | 7777, |
1162 | ObjectPath::from_static_str("/" ).unwrap(), |
1163 | 8888 |
1164 | )) |
1165 | .to_string(), |
1166 | s, |
1167 | ); |
1168 | } |
1169 | } |
1170 | } |
1171 | |