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