1 | use std::num::NonZeroU32; |
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 static_assertions::assert_impl_all; |
10 | use zbus_names::{BusName, ErrorName, InterfaceName, MemberName, UniqueName}; |
11 | use 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)] |
24 | pub(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 | |
45 | assert_impl_all!(FieldCode: Send, Sync, Unpin); |
46 | |
47 | impl<'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)] |
76 | pub(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 | |
97 | assert_impl_all!(Field<'_>: Send, Sync, Unpin); |
98 | |
99 | impl<'f> Type for Field<'f> { |
100 | fn signature() -> Signature<'static> { |
101 | Signature::from_static_str_unchecked(signature:"(yv)" ) |
102 | } |
103 | } |
104 | |
105 | impl<'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: &ObjectPath<'_>) => (FieldCode::Path, value.as_ref().into()), |
112 | Field::Interface(value: &InterfaceName<'_>) => (FieldCode::Interface, value.as_str().into()), |
113 | Field::Member(value: &MemberName<'_>) => (FieldCode::Member, value.as_str().into()), |
114 | Field::ErrorName(value: &ErrorName<'_>) => (FieldCode::ErrorName, value.as_str().into()), |
115 | Field::ReplySerial(value: &NonZero) => (FieldCode::ReplySerial, value.get().into()), |
116 | Field::Destination(value: &BusName<'_>) => (FieldCode::Destination, value.as_str().into()), |
117 | Field::Sender(value: &UniqueName<'_>) => (FieldCode::Sender, value.as_str().into()), |
118 | Field::Signature(value: &Signature<'_>) => (FieldCode::Signature, value.as_ref().into()), |
119 | Field::UnixFDs(value: &u32) => (FieldCode::UnixFDs, (*value).into()), |
120 | }; |
121 | |
122 | tuple.serialize(serializer) |
123 | } |
124 | } |
125 | |
126 | impl<'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 | } |
168 | |