zvariant/
structure.rs

1#![allow(unknown_lints)]
2use serde::{
3    de::{DeserializeSeed, Deserializer, SeqAccess, Visitor},
4    ser::{Serialize, SerializeTupleStruct, Serializer},
5};
6use static_assertions::assert_impl_all;
7use std::{
8    convert::TryInto,
9    fmt::{Display, Write},
10};
11
12use crate::{
13    signature_parser::SignatureParser, value::SignatureSeed, value_display_fmt, DynamicDeserialize,
14    DynamicType, OwnedValue, Signature, Value,
15};
16
17/// Use this to efficiently build a [`Structure`].
18///
19/// [`Structure`]: struct.Structure.html
20#[derive(Debug, Default, Clone, PartialEq)]
21pub struct StructureBuilder<'a>(Vec<Value<'a>>);
22
23assert_impl_all!(StructureBuilder<'_>: Send, Sync, Unpin);
24
25impl<'a> StructureBuilder<'a> {
26    /// Create a new `StructureBuilder`.
27    ///
28    /// Same as `StructureBuilder::default()`.
29    pub fn new() -> Self {
30        Self::default()
31    }
32
33    /// Append `field` to `self`.
34    ///
35    /// This method returns `Self` so that you can use the builder pattern to create a complex
36    /// structure.
37    #[must_use]
38    pub fn add_field<T>(self, field: T) -> Self
39    where
40        T: DynamicType + Into<Value<'a>>,
41    {
42        self.append_field(Value::new(field))
43    }
44
45    /// Append `field` to `self`.
46    ///
47    /// Identical to `add_field`, except the field must be in the form of a `Value`.
48    #[must_use]
49    pub fn append_field<'e: 'a>(mut self, field: Value<'e>) -> Self {
50        self.0.push(field);
51
52        self
53    }
54
55    /// Append `field` to `self`.
56    ///
57    /// Identical to `add_field`, except it makes changes in-place.
58    pub fn push_field<T>(&mut self, field: T)
59    where
60        T: DynamicType + Into<Value<'a>>,
61    {
62        self.push_value(Value::new(field))
63    }
64
65    /// Append `field` to `self`.
66    ///
67    /// Identical to `append_field`, except it makes changes in-place.
68    pub fn push_value<'e: 'a>(&mut self, field: Value<'e>) {
69        self.0.push(field)
70    }
71
72    /// Build the `Structure`.
73    ///
74    /// [`Structure`]: struct.Structure.html
75    pub fn build(self) -> Structure<'a> {
76        let signature = create_signature_from_fields(&self.0);
77
78        Structure {
79            fields: self.0,
80            signature,
81        }
82    }
83
84    /// Same as `build` except Signature is provided.
85    pub(crate) fn build_with_signature<'s: 'a>(self, signature: Signature<'s>) -> Structure<'a> {
86        Structure {
87            fields: self.0,
88            signature,
89        }
90    }
91}
92
93/// Use this to deserialize a [`Structure`].
94///
95/// [`Structure`]: struct.Structure.html
96#[derive(Debug, Clone, PartialEq, Eq)]
97pub struct StructureSeed<'a>(Signature<'a>);
98
99assert_impl_all!(StructureSeed<'_>: Send, Sync, Unpin);
100
101impl<'a> StructureSeed<'a> {
102    /// Create a new `StructureSeed`
103    ///
104    /// The given signature must be a valid structure signature.
105    #[must_use]
106    pub fn new_unchecked(signature: Signature<'a>) -> Self {
107        StructureSeed(signature)
108    }
109}
110
111impl<'a> std::convert::TryFrom<Signature<'a>> for StructureSeed<'a> {
112    type Error = zvariant::Error;
113
114    fn try_from(signature: Signature<'a>) -> Result<Self, zvariant::Error> {
115        if signature.starts_with(zvariant::STRUCT_SIG_START_CHAR) {
116            Ok(StructureSeed(signature))
117        } else {
118            Err(zvariant::Error::IncorrectType)
119        }
120    }
121}
122
123impl<'de> DeserializeSeed<'de> for StructureSeed<'de> {
124    type Value = Structure<'de>;
125    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
126    where
127        D: Deserializer<'de>,
128    {
129        deserializer.deserialize_seq(StructureVisitor { signature: self.0 })
130    }
131}
132
133#[derive(Debug, Clone, PartialEq, Eq)]
134struct StructureVisitor<'a> {
135    signature: Signature<'a>,
136}
137
138impl<'de> Visitor<'de> for StructureVisitor<'de> {
139    type Value = Structure<'de>;
140
141    fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142        formatter.write_str("a Structure value")
143    }
144
145    fn visit_seq<V>(self, visitor: V) -> Result<Structure<'de>, V::Error>
146    where
147        V: SeqAccess<'de>,
148    {
149        SignatureSeed {
150            signature: self.signature,
151        }
152        .visit_struct(visitor)
153    }
154}
155
156/// A helper type to wrap structs in [`Value`].
157///
158/// API is provided to convert from, and to tuples.
159///
160/// [`Value`]: enum.Value.html
161#[derive(Debug, Clone, PartialEq)]
162pub struct Structure<'a> {
163    fields: Vec<Value<'a>>,
164    signature: Signature<'a>,
165}
166
167assert_impl_all!(Structure<'_>: Send, Sync, Unpin);
168
169impl<'a> Structure<'a> {
170    /// Get a reference to all the fields of `self`.
171    pub fn fields(&self) -> &[Value<'a>] {
172        &self.fields
173    }
174
175    /// Converts `self` to a `Vec` containing all its fields.
176    pub fn into_fields(self) -> Vec<Value<'a>> {
177        self.fields
178    }
179
180    /// Get the signature of this `Structure`.
181    ///
182    /// NB: This method potentially allocates and copies. Use [`full_signature`] if you'd like to
183    /// avoid that.
184    ///
185    /// [`full_signature`]: #method.full_signature
186    pub fn signature(&self) -> Signature<'static> {
187        self.signature.to_owned()
188    }
189
190    /// Get the signature of this `Structure`.
191    pub fn full_signature(&self) -> &Signature<'_> {
192        &self.signature
193    }
194
195    pub(crate) fn to_owned(&self) -> Structure<'static> {
196        Structure {
197            fields: self.fields.iter().map(|v| v.to_owned().into()).collect(),
198            signature: self.signature.to_owned(),
199        }
200    }
201}
202
203impl Display for Structure<'_> {
204    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
205        structure_display_fmt(self, f, true)
206    }
207}
208
209pub(crate) fn structure_display_fmt(
210    structure: &Structure<'_>,
211    f: &mut std::fmt::Formatter<'_>,
212    type_annotate: bool,
213) -> std::fmt::Result {
214    f.write_char('(')?;
215
216    let fields = structure.fields();
217
218    match fields.len() {
219        0 => {}
220        1 => {
221            value_display_fmt(&fields[0], f, type_annotate)?;
222            f.write_char(',')?;
223        }
224        _ => {
225            for (i, field) in fields.iter().enumerate() {
226                value_display_fmt(field, f, type_annotate)?;
227
228                if i + 1 < fields.len() {
229                    f.write_str(", ")?;
230                }
231            }
232        }
233    }
234
235    f.write_char(')')
236}
237
238impl<'a> Default for Structure<'a> {
239    fn default() -> Self {
240        let signature = Signature::from_static_str_unchecked("()");
241
242        Self {
243            fields: vec![],
244            signature,
245        }
246    }
247}
248
249impl<'a> DynamicType for Structure<'a> {
250    fn dynamic_signature(&self) -> Signature<'_> {
251        self.signature.clone()
252    }
253}
254
255impl<'a> DynamicType for StructureSeed<'a> {
256    fn dynamic_signature(&self) -> Signature<'_> {
257        self.0.clone()
258    }
259}
260
261impl<'a> DynamicDeserialize<'a> for Structure<'a> {
262    type Deserializer = StructureSeed<'a>;
263
264    fn deserializer_for_signature<S>(signature: S) -> zvariant::Result<Self::Deserializer>
265    where
266        S: TryInto<Signature<'a>>,
267        S::Error: Into<zvariant::Error>,
268    {
269        let mut signature = signature.try_into().map_err(Into::into)?;
270        if !signature.starts_with(zvariant::STRUCT_SIG_START_CHAR) {
271            // This is certainly not a valid struct signature
272            signature = format!("({signature})").try_into()?;
273            return signature.try_into();
274        }
275
276        // The signature might be something like "(i)u(i)" - we need to parse it to check.
277        let mut parser = SignatureParser::new(signature.clone());
278        parser.parse_next_signature()?;
279        if !parser.done() {
280            // more than one element - we must wrap it
281            signature = format!("({signature})").try_into()?;
282        }
283        signature.try_into()
284    }
285}
286
287impl<'a> Serialize for Structure<'a> {
288    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
289    where
290        S: Serializer,
291    {
292        let mut structure =
293            serializer.serialize_tuple_struct("zvariant::Structure", self.fields.len())?;
294        for field in &self.fields {
295            field.serialize_value_as_tuple_struct_field(&mut structure)?;
296        }
297        structure.end()
298    }
299}
300
301macro_rules! tuple_impls {
302    ($($len:expr => ($($n:tt $name:ident)+))+) => {
303        $(
304            impl<'a, $($name),+> From<($($name),+,)> for Structure<'a>
305            where
306                $($name: DynamicType + Into<Value<'a>>,)+
307            {
308                #[inline]
309                fn from(value: ($($name),+,)) -> Self {
310                    StructureBuilder::new()
311                    $(
312                        .add_field(value. $n)
313                    )+
314                    .build()
315                }
316            }
317
318            impl<'a, E, $($name),+> std::convert::TryFrom<Structure<'a>> for ($($name),+,)
319            where
320                $($name: std::convert::TryFrom<Value<'a>, Error = E>,)+
321                crate::Error: From<E>,
322
323            {
324                type Error = crate::Error;
325
326                fn try_from(mut s: Structure<'a>) -> core::result::Result<Self, Self::Error> {
327                    Ok((
328                    $(
329                         $name::try_from(s.fields.remove(0))?,
330                    )+
331                    ))
332                }
333            }
334
335            impl<'a, E, $($name),+> std::convert::TryFrom<Value<'a>> for ($($name),+,)
336            where
337                $($name: std::convert::TryFrom<Value<'a>, Error = E>,)+
338                crate::Error: From<E>,
339
340            {
341                type Error = crate::Error;
342
343                fn try_from(v: Value<'a>) -> core::result::Result<Self, Self::Error> {
344                    Self::try_from(Structure::try_from(v)?)
345                }
346            }
347
348            impl<E, $($name),+> std::convert::TryFrom<OwnedValue> for ($($name),+,)
349            where
350                $($name: std::convert::TryFrom<Value<'static>, Error = E>,)+
351                crate::Error: From<E>,
352
353            {
354                type Error = crate::Error;
355
356                fn try_from(v: OwnedValue) -> core::result::Result<Self, Self::Error> {
357                    Self::try_from(Value::from(v))
358                }
359            }
360        )+
361    }
362}
363
364tuple_impls! {
365    1 => (0 T0)
366    2 => (0 T0 1 T1)
367    3 => (0 T0 1 T1 2 T2)
368    4 => (0 T0 1 T1 2 T2 3 T3)
369    5 => (0 T0 1 T1 2 T2 3 T3 4 T4)
370    6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
371    7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
372    8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
373    9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
374    10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
375    11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
376    12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
377    13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12)
378    14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13)
379    15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14)
380    16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15)
381}
382
383fn create_signature_from_fields(fields: &[Value<'_>]) -> Signature<'static> {
384    let mut signature = String::with_capacity(255);
385    signature.push('(');
386    for field in fields {
387        signature.push_str(&field.value_signature());
388    }
389    signature.push(')');
390
391    Signature::from_string_unchecked(signature)
392}