Skip to main content

tokio_dbus_runtime/
value.rs

1use std::fmt::{self, Display};
2
3use tokio_dbus::{
4    Alignment, Body, ObjectPath, ObjectPathBuf, Raw, Signature, SignatureBuf, SignatureBuilder,
5};
6use tokio_dbus_core::signature;
7
8use crate::error::ErrorKind;
9use crate::{Decode, Encode, Error, Result};
10
11/// A D-Bus value whose type is only known at runtime.
12///
13/// This is what a `v` in a signature is decoded into, and holds the value that
14/// was inside the variant rather than the variant itself. A [`Value::Variant`]
15/// is therefore only produced for a variant nested inside another one.
16///
17/// # Examples
18///
19/// ```
20/// use std::collections::HashMap;
21///
22/// use tokio_dbus_runtime::Value;
23///
24/// let mut hints = HashMap::new();
25/// hints.insert(String::from("urgency"), Value::U8(2));
26/// hints.insert(String::from("category"), Value::String("device".into()));
27///
28/// assert_eq!(hints["urgency"].signature()?, "y");
29/// assert_eq!(hints["category"].signature()?, "s");
30/// # Ok::<_, tokio_dbus_runtime::Error>(())
31/// ```
32// NB: The container variants carry the signature of what they hold, which makes
33// them a good deal larger than the scalar ones. Boxing them would cost an
34// allocation on every value in a message for no practical gain.
35#[allow(clippy::large_enum_variant)]
36#[derive(Debug, Clone, PartialEq)]
37#[non_exhaustive]
38pub enum Value {
39    /// A boolean.
40    Bool(bool),
41    /// A single byte.
42    U8(u8),
43    /// A signed 16-bit integer.
44    I16(i16),
45    /// An unsigned 16-bit integer.
46    U16(u16),
47    /// A signed 32-bit integer.
48    I32(i32),
49    /// An unsigned 32-bit integer.
50    U32(u32),
51    /// A signed 64-bit integer.
52    I64(i64),
53    /// An unsigned 64-bit integer.
54    U64(u64),
55    /// A 64-bit floating point number.
56    F64(f64),
57    /// A string.
58    String(String),
59    /// An object path.
60    ObjectPath(ObjectPathBuf),
61    /// A signature.
62    Signature(SignatureBuf),
63    /// An array.
64    ///
65    /// The signature of the element type is carried along, since it cannot be
66    /// recovered from the values when the array is empty.
67    Array {
68        /// The type of each element.
69        element: SignatureBuf,
70        /// The elements.
71        values: Vec<Value>,
72    },
73    /// A dictionary, which on the wire is an array of key and value pairs.
74    Dict {
75        /// The type of each key.
76        key: SignatureBuf,
77        /// The type of each value.
78        value: SignatureBuf,
79        /// The entries, in the order they appeared.
80        entries: Vec<(Value, Value)>,
81    },
82    /// A struct.
83    Struct(Vec<Value>),
84    /// A variant nested inside of another value.
85    Variant(Box<Value>),
86}
87
88impl Value {
89    /// Construct an empty array of the given element type.
90    ///
91    /// # Examples
92    ///
93    /// ```
94    /// use tokio_dbus_runtime::Value;
95    ///
96    /// let value = Value::array("(iiay)")?;
97    /// assert_eq!(value.signature()?, "a(iiay)");
98    /// # Ok::<_, tokio_dbus_runtime::Error>(())
99    /// ```
100    pub fn array(element: &str) -> Result<Self> {
101        Ok(Value::Array {
102            element: Signature::new(element)?.to_owned(),
103            values: Vec::new(),
104        })
105    }
106
107    /// The signature of this value.
108    ///
109    /// # Examples
110    ///
111    /// ```
112    /// use tokio_dbus_runtime::Value;
113    ///
114    /// let value = Value::Struct(vec![Value::I32(1), Value::String("hi".into())]);
115    /// assert_eq!(value.signature()?, "(is)");
116    /// # Ok::<_, tokio_dbus_runtime::Error>(())
117    /// ```
118    pub fn signature(&self) -> Result<SignatureBuf> {
119        let mut builder = SignatureBuilder::new();
120        self.write_signature(&mut builder)?;
121        Ok(builder.to_signature().to_owned())
122    }
123
124    fn write_signature(&self, builder: &mut SignatureBuilder) -> Result<()> {
125        fn extend(builder: &mut SignatureBuilder, signature: &Signature) -> Result<()> {
126            if !builder.extend_from_signature(signature) {
127                return Err(Error::from(tokio_dbus::SignatureError::too_long()));
128            }
129
130            Ok(())
131        }
132
133        match self {
134            Value::Bool(..) => extend(builder, Signature::BOOLEAN)?,
135            Value::U8(..) => extend(builder, Signature::BYTE)?,
136            Value::I16(..) => extend(builder, Signature::INT16)?,
137            Value::U16(..) => extend(builder, Signature::UINT16)?,
138            Value::I32(..) => extend(builder, Signature::INT32)?,
139            Value::U32(..) => extend(builder, Signature::UINT32)?,
140            Value::I64(..) => extend(builder, Signature::INT64)?,
141            Value::U64(..) => extend(builder, Signature::UINT64)?,
142            Value::F64(..) => extend(builder, Signature::DOUBLE)?,
143            Value::String(..) => extend(builder, Signature::STRING)?,
144            Value::ObjectPath(..) => extend(builder, Signature::OBJECT_PATH)?,
145            Value::Signature(..) => extend(builder, Signature::SIGNATURE)?,
146            Value::Array { element, .. } => {
147                builder.open_array()?;
148                extend(builder, element)?;
149                builder.close_array();
150            }
151            Value::Dict { key, value, .. } => {
152                builder.open_array()?;
153                builder.open_dict()?;
154                extend(builder, key)?;
155                extend(builder, value)?;
156                builder.close_dict()?;
157                builder.close_array();
158            }
159            Value::Struct(fields) => {
160                builder.open_struct()?;
161
162                for field in fields {
163                    field.write_signature(builder)?;
164                }
165
166                builder.close_struct()?;
167            }
168            Value::Variant(..) => extend(builder, Signature::VARIANT)?,
169        }
170
171        Ok(())
172    }
173
174    /// Write the value without its signature.
175    pub(crate) fn encode_value(&self, raw: &mut Raw<'_>) {
176        match self {
177            Value::Bool(value) => raw.store(*value),
178            Value::U8(value) => raw.store(*value),
179            Value::I16(value) => raw.store(*value),
180            Value::U16(value) => raw.store(*value),
181            Value::I32(value) => raw.store(*value),
182            Value::U32(value) => raw.store(*value),
183            Value::I64(value) => raw.store(*value),
184            Value::U64(value) => raw.store(*value),
185            Value::F64(value) => raw.store(*value),
186            Value::String(value) => raw.store(value.as_str()),
187            Value::ObjectPath(value) => raw.store(&**value),
188            Value::Signature(value) => raw.store(&**value),
189            Value::Array { element, values } => {
190                let mut array = raw.store_array(alignment_of(element));
191
192                for value in values {
193                    encode_element(value, element, &mut array.as_raw());
194                }
195            }
196            Value::Dict {
197                value: signature,
198                entries,
199                ..
200            } => {
201                let mut array = raw.store_array(Alignment::U64);
202
203                for (key, value) in entries {
204                    let mut entry = array.as_raw();
205                    entry.align(Alignment::U64);
206                    key.encode_value(&mut entry);
207                    encode_element(value, signature, &mut entry);
208                }
209            }
210            Value::Struct(fields) => {
211                raw.align(Alignment::U64);
212
213                for field in fields {
214                    field.encode_value(raw);
215                }
216            }
217            Value::Variant(value) => {
218                // NB: This is the signature of the value inside the nested
219                // variant, which is data rather than part of the signature of
220                // the surrounding buffer.
221                if let Ok(signature) = value.signature() {
222                    raw.store_signature(&signature);
223                    value.encode_value(raw);
224                }
225            }
226        }
227    }
228
229    /// Read a value whose type is described by `signature`, which must name
230    /// exactly one type.
231    pub(crate) fn decode_as(body: &mut Body<'_>, signature: &Signature) -> Result<Value> {
232        let mut iter = signature.iter();
233
234        let Some(ty) = iter.next() else {
235            return Err(Error::new(ErrorKind::UnsupportedType(Box::new(
236                signature.to_owned(),
237            ))));
238        };
239
240        if iter.next().is_some() {
241            // NB: A variant holds exactly one value, so a signature naming more
242            // than one type cannot be decoded into a single value.
243            return Err(Error::new(ErrorKind::UnsupportedType(Box::new(
244                signature.to_owned(),
245            ))));
246        }
247
248        Value::decode_type(body, ty)
249    }
250
251    fn decode_type(body: &mut Body<'_>, ty: signature::Type<'_>) -> Result<Value> {
252        match ty {
253            signature::Type::Signature(signature) => match signature.as_bytes() {
254                b"b" => Ok(Value::Bool(body.load_bool()?)),
255                b"y" => Ok(Value::U8(body.load()?)),
256                b"n" => Ok(Value::I16(body.load()?)),
257                b"q" => Ok(Value::U16(body.load()?)),
258                b"i" => Ok(Value::I32(body.load()?)),
259                b"u" => Ok(Value::U32(body.load()?)),
260                b"x" => Ok(Value::I64(body.load()?)),
261                b"t" => Ok(Value::U64(body.load()?)),
262                b"d" => Ok(Value::F64(body.load()?)),
263                b"s" => Ok(Value::String(body.read::<str>()?.to_owned())),
264                b"o" => Ok(Value::ObjectPath(body.read::<ObjectPath>()?.to_owned())),
265                b"g" => Ok(Value::Signature(body.read::<Signature>()?.to_owned())),
266                b"v" => {
267                    let inner = body.read::<Signature>()?;
268                    Ok(Value::Variant(Box::new(Value::decode_as(body, inner)?)))
269                }
270                _ => Err(Error::new(ErrorKind::UnsupportedType(Box::new(
271                    signature.to_owned(),
272                )))),
273            },
274            signature::Type::Array(element) => {
275                let mut array = body.load_raw_array(alignment_of(element))?;
276
277                // NB: A dict entry is only legal as the element type of an
278                // array, which is why it is handled here rather than as a type
279                // of its own.
280                if let Some(signature::Type::Dict(key, value)) = single(element) {
281                    let mut entries = Vec::new();
282
283                    while !array.is_empty() {
284                        array.align_to(Alignment::U64)?;
285                        let key = Value::decode_as(&mut array, key)?;
286                        let value = Value::decode_as(&mut array, value)?;
287                        entries.push((key, value));
288                    }
289
290                    return Ok(Value::Dict {
291                        key: key.to_owned(),
292                        value: value.to_owned(),
293                        entries,
294                    });
295                }
296
297                let mut values = Vec::new();
298
299                while !array.is_empty() {
300                    values.push(Value::decode_as(&mut array, element)?);
301                }
302
303                Ok(Value::Array {
304                    element: element.to_owned(),
305                    values,
306                })
307            }
308            signature::Type::Struct(fields) => {
309                body.align_to(Alignment::U64)?;
310                let mut values = Vec::new();
311
312                for field in fields.iter() {
313                    values.push(Value::decode_type(body, field)?);
314                }
315
316                Ok(Value::Struct(values))
317            }
318            signature::Type::Dict(key, value) => {
319                body.align_to(Alignment::U64)?;
320                let key = Value::decode_as(body, key)?;
321                let value = Value::decode_as(body, value)?;
322                Ok(Value::Struct(vec![key, value]))
323            }
324        }
325    }
326}
327
328/// The single type named by a signature, if it names exactly one.
329fn single(signature: &Signature) -> Option<signature::Type<'_>> {
330    let mut iter = signature.iter();
331    let ty = iter.next()?;
332
333    if iter.next().is_some() {
334        return None;
335    }
336
337    Some(ty)
338}
339
340/// Write one element of a container whose declared element type is
341/// `signature`.
342///
343/// A value sitting in a variant position carries its own signature, which is
344/// why both a value wrapped in [`Value::Variant`] and a bare one are accepted
345/// there. Decoding produces the wrapped form.
346fn encode_element(value: &Value, signature: &Signature, raw: &mut Raw<'_>) {
347    if signature.as_bytes() != b"v" {
348        value.encode_value(raw);
349        return;
350    }
351
352    match value {
353        Value::Variant(inner) => inner.encode(raw),
354        value => value.encode(raw),
355    }
356}
357
358/// The alignment of the first type in a signature.
359pub(crate) fn alignment_of(signature: &Signature) -> Alignment {
360    match signature.as_bytes().first() {
361        Some(b'y' | b'g' | b'v') => Alignment::BYTE,
362        Some(b'n' | b'q') => Alignment::U16,
363        Some(b'x' | b't' | b'd' | b'(' | b'{') => Alignment::U64,
364        _ => Alignment::U32,
365    }
366}
367
368impl Encode for Value {
369    // NB: A variant starts with the signature of the value it contains, which is
370    // prefixed by a single byte holding its length.
371    const ALIGNMENT: Alignment = Alignment::BYTE;
372
373    fn encode(&self, raw: &mut Raw<'_>) {
374        if let Ok(signature) = self.signature() {
375            raw.store_signature(&signature);
376            self.encode_value(raw);
377        }
378    }
379}
380
381impl Decode for Value {
382    const ALIGNMENT: Alignment = Alignment::BYTE;
383
384    fn decode(body: &mut Body<'_>) -> Result<Self> {
385        let signature = body.read::<Signature>()?;
386        Value::decode_as(body, signature)
387    }
388}
389
390impl fmt::Display for Value {
391    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
392        match self {
393            Value::Bool(value) => value.fmt(f),
394            Value::U8(value) => value.fmt(f),
395            Value::I16(value) => value.fmt(f),
396            Value::U16(value) => value.fmt(f),
397            Value::I32(value) => value.fmt(f),
398            Value::U32(value) => value.fmt(f),
399            Value::I64(value) => value.fmt(f),
400            Value::U64(value) => value.fmt(f),
401            Value::F64(value) => value.fmt(f),
402            Value::String(value) => value.fmt(f),
403            Value::ObjectPath(value) => value.fmt(f),
404            Value::Signature(value) => value.fmt(f),
405            Value::Array { values, .. } => write_all(f, values.iter(), "[", "]"),
406            Value::Dict { entries, .. } => {
407                f.write_str("{")?;
408
409                for (index, (key, value)) in entries.iter().enumerate() {
410                    if index > 0 {
411                        f.write_str(", ")?;
412                    }
413
414                    write!(f, "{key}: {value}")?;
415                }
416
417                f.write_str("}")
418            }
419            Value::Struct(fields) => write_all(f, fields.iter(), "(", ")"),
420            Value::Variant(value) => value.fmt(f),
421        }
422    }
423}
424
425fn write_all<'a, I>(f: &mut fmt::Formatter<'_>, values: I, open: &str, close: &str) -> fmt::Result
426where
427    I: Iterator<Item = &'a Value>,
428{
429    f.write_str(open)?;
430
431    for (index, value) in values.enumerate() {
432        if index > 0 {
433            f.write_str(", ")?;
434        }
435
436        value.fmt(f)?;
437    }
438
439    f.write_str(close)
440}