zbus/message/
field.rs

1use std::num::NonZeroU32;
2
3use serde::{
4    de::{Deserialize, Deserializer, Error},
5    ser::{Serialize, Serializer},
6};
7use serde_repr::{Deserialize_repr, Serialize_repr};
8
9use static_assertions::assert_impl_all;
10use zbus_names::{BusName, ErrorName, InterfaceName, MemberName, UniqueName};
11use zvariant::{ObjectPath, Signature, Type, Value};
12
13/// The message field code.
14///
15/// Every [`Field`] has an associated code. This is mostly an internal D-Bus protocol detail
16/// that you would not need to ever care about when using the high-level API. When using the
17/// low-level API, this is how you can [retrieve a specific field] from [`Fields`].
18///
19/// [`Field`]: enum.Field.html
20/// [retrieve a specific field]: struct.Fields.html#method.get_field
21/// [`Fields`]: struct.Fields.html
22#[repr(u8)]
23#[derive(Copy, Clone, Debug, Deserialize_repr, PartialEq, Eq, Serialize_repr, Type)]
24pub(crate) enum FieldCode {
25    /// Code for [`Field::Path`](enum.Field.html#variant.Path)
26    Path = 1,
27    /// Code for [`Field::Interface`](enum.Field.html#variant.Interface)
28    Interface = 2,
29    /// Code for [`Field::Member`](enum.Field.html#variant.Member)
30    Member = 3,
31    /// Code for [`Field::ErrorName`](enum.Field.html#variant.ErrorName)
32    ErrorName = 4,
33    /// Code for [`Field::ReplySerial`](enum.Field.html#variant.ReplySerial)
34    ReplySerial = 5,
35    /// Code for [`Field::Destination`](enum.Field.html#variant.Destination)
36    Destination = 6,
37    /// Code for [`Field::Sender`](enum.Field.html#variant.Sender)
38    Sender = 7,
39    /// Code for [`Field::Signature`](enum.Field.html#variant.Signature)
40    Signature = 8,
41    /// Code for [`Field::UnixFDs`](enum.Field.html#variant.UnixFDs)
42    UnixFDs = 9,
43}
44
45assert_impl_all!(FieldCode: Send, Sync, Unpin);
46
47impl<'f> Field<'f> {
48    /// Get the associated code for this field.
49    pub fn code(&self) -> FieldCode {
50        match self {
51            Field::Path(_) => FieldCode::Path,
52            Field::Interface(_) => FieldCode::Interface,
53            Field::Member(_) => FieldCode::Member,
54            Field::ErrorName(_) => FieldCode::ErrorName,
55            Field::ReplySerial(_) => FieldCode::ReplySerial,
56            Field::Destination(_) => FieldCode::Destination,
57            Field::Sender(_) => FieldCode::Sender,
58            Field::Signature(_) => FieldCode::Signature,
59            Field::UnixFDs(_) => FieldCode::UnixFDs,
60        }
61    }
62}
63
64/// The dynamic message header.
65///
66/// All D-Bus messages contain a set of metadata [headers]. Some of these headers [are fixed] for
67/// all types of messages, while others depend on the type of the message in question. The latter
68/// are called message fields.
69///
70/// Please consult the [Message Format] section of the D-Bus spec for more details.
71///
72/// [headers]: struct.Header.html
73/// [are fixed]: struct.PrimaryHeader.html
74/// [Message Format]: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
75#[derive(Clone, Debug, PartialEq, Eq)]
76pub(crate) enum Field<'f> {
77    /// The object to send a call to, or the object a signal is emitted from.
78    Path(ObjectPath<'f>),
79    /// The interface to invoke a method call on, or that a signal is emitted from.
80    Interface(InterfaceName<'f>),
81    /// The member, either the method name or signal name.
82    Member(MemberName<'f>),
83    /// The name of the error that occurred, for errors
84    ErrorName(ErrorName<'f>),
85    /// The serial number of the message this message is a reply to.
86    ReplySerial(NonZeroU32),
87    /// The name of the connection this message is intended for.
88    Destination(BusName<'f>),
89    /// Unique name of the sending connection.
90    Sender(UniqueName<'f>),
91    /// The signature of the message body.
92    Signature(Signature<'f>),
93    /// The number of Unix file descriptors that accompany the message.
94    UnixFDs(u32),
95}
96
97assert_impl_all!(Field<'_>: Send, Sync, Unpin);
98
99impl<'f> Type for Field<'f> {
100    fn signature() -> Signature<'static> {
101        Signature::from_static_str_unchecked("(yv)")
102    }
103}
104
105impl<'f> Serialize for Field<'f> {
106    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
107    where
108        S: Serializer,
109    {
110        let tuple: (FieldCode, Value<'_>) = match self {
111            Field::Path(value) => (FieldCode::Path, value.as_ref().into()),
112            Field::Interface(value) => (FieldCode::Interface, value.as_str().into()),
113            Field::Member(value) => (FieldCode::Member, value.as_str().into()),
114            Field::ErrorName(value) => (FieldCode::ErrorName, value.as_str().into()),
115            Field::ReplySerial(value) => (FieldCode::ReplySerial, value.get().into()),
116            Field::Destination(value) => (FieldCode::Destination, value.as_str().into()),
117            Field::Sender(value) => (FieldCode::Sender, value.as_str().into()),
118            Field::Signature(value) => (FieldCode::Signature, value.as_ref().into()),
119            Field::UnixFDs(value) => (FieldCode::UnixFDs, (*value).into()),
120        };
121
122        tuple.serialize(serializer)
123    }
124}
125
126impl<'de: 'f, 'f> Deserialize<'de> for Field<'f> {
127    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
128    where
129        D: Deserializer<'de>,
130    {
131        let (code, value) = <(FieldCode, Value<'_>)>::deserialize(deserializer)?;
132        Ok(match code {
133            FieldCode::Path => Field::Path(ObjectPath::try_from(value).map_err(D::Error::custom)?),
134            FieldCode::Interface => {
135                Field::Interface(InterfaceName::try_from(value).map_err(D::Error::custom)?)
136            }
137            FieldCode::Member => {
138                Field::Member(MemberName::try_from(value).map_err(D::Error::custom)?)
139            }
140            FieldCode::ErrorName => Field::ErrorName(
141                ErrorName::try_from(value)
142                    .map(Into::into)
143                    .map_err(D::Error::custom)?,
144            ),
145            FieldCode::ReplySerial => {
146                let value = u32::try_from(value)
147                    .map_err(D::Error::custom)
148                    .and_then(|v| v.try_into().map_err(D::Error::custom))?;
149                Field::ReplySerial(value)
150            }
151            FieldCode::Destination => Field::Destination(
152                BusName::try_from(value)
153                    .map(Into::into)
154                    .map_err(D::Error::custom)?,
155            ),
156            FieldCode::Sender => Field::Sender(
157                UniqueName::try_from(value)
158                    .map(Into::into)
159                    .map_err(D::Error::custom)?,
160            ),
161            FieldCode::Signature => {
162                Field::Signature(Signature::try_from(value).map_err(D::Error::custom)?)
163            }
164            FieldCode::UnixFDs => Field::UnixFDs(u32::try_from(value).map_err(D::Error::custom)?),
165        })
166    }
167}