1 #![deny(rust_2018_idioms)]
2 #![doc(
3     html_logo_url = "https://storage.googleapis.com/fdo-gitlab-uploads/project/avatar/3213/zbus-logomark.png"
4 )]
5 #![doc = include_str!("../README.md")]
6 
7 #[cfg(doctest)]
8 mod doctests {
9     doc_comment::doctest!("../README.md");
10 }
11 
12 use proc_macro::TokenStream;
13 use syn::{self, DeriveInput};
14 
15 mod dict;
16 mod r#type;
17 mod utils;
18 mod value;
19 
20 /// Derive macro to add [`Type`] implementation to structs and enums.
21 ///
22 /// # Examples
23 ///
24 /// For structs it works just like serde's [`Serialize`] and [`Deserialize`] macros:
25 ///
26 /// ```
27 /// use zvariant::{EncodingContext, from_slice, to_bytes, Type};
28 /// use serde::{Deserialize, Serialize};
29 /// use byteorder::LE;
30 ///
31 /// #[derive(Deserialize, Serialize, Type, PartialEq, Debug)]
32 /// struct Struct<'s> {
33 ///     field1: u16,
34 ///     field2: i64,
35 ///     field3: &'s str,
36 /// }
37 ///
38 /// assert_eq!(Struct::signature(), "(qxs)");
39 /// let s = Struct {
40 ///     field1: 42,
41 ///     field2: i64::max_value(),
42 ///     field3: "hello",
43 /// };
44 /// let ctxt = EncodingContext::<LE>::new_dbus(0);
45 /// let encoded = to_bytes(ctxt, &s).unwrap();
46 /// let decoded: Struct = from_slice(&encoded, ctxt).unwrap();
47 /// assert_eq!(decoded, s);
48 /// ```
49 ///
50 /// Same with enum, except that only enums with unit variants are supported. If you want the
51 /// encoding size of the enum to be dictated by `repr` attribute (like in the example below),
52 /// you'll also need [serde_repr] crate.
53 ///
54 /// ```
55 /// use zvariant::{EncodingContext, from_slice, to_bytes, Type};
56 /// use serde::{Deserialize, Serialize};
57 /// use serde_repr::{Deserialize_repr, Serialize_repr};
58 /// use byteorder::LE;
59 ///
60 /// #[repr(u8)]
61 /// #[derive(Deserialize_repr, Serialize_repr, Type, Debug, PartialEq)]
62 /// enum Enum {
63 ///     Variant1,
64 ///     Variant2,
65 /// }
66 /// assert_eq!(Enum::signature(), u8::signature());
67 /// let ctxt = EncodingContext::<LE>::new_dbus(0);
68 /// let encoded = to_bytes(ctxt, &Enum::Variant2).unwrap();
69 /// let decoded: Enum = from_slice(&encoded, ctxt).unwrap();
70 /// assert_eq!(decoded, Enum::Variant2);
71 ///
72 /// #[repr(i64)]
73 /// #[derive(Deserialize_repr, Serialize_repr, Type)]
74 /// enum Enum2 {
75 ///     Variant1,
76 ///     Variant2,
77 /// }
78 /// assert_eq!(Enum2::signature(), i64::signature());
79 ///
80 /// // w/o repr attribute, u32 representation is chosen
81 /// #[derive(Deserialize, Serialize, Type)]
82 /// enum NoReprEnum {
83 ///     Variant1,
84 ///     Variant2,
85 /// }
86 /// assert_eq!(NoReprEnum::signature(), u32::signature());
87 /// ```
88 ///
89 /// # Custom signatures
90 ///
91 /// There are times when you'd find yourself wanting to specify a hardcoded signature yourself for
92 /// the type. The `signature` attribute exists for this purpose. A typical use case is when you'd
93 /// need to encode your type as a dictionary (signature `a{sv}`) type. For convenience, `dict` is
94 /// an alias for `a{sv}`. Here is an example:
95 ///
96 /// ```
97 /// use zvariant::{SerializeDict, DeserializeDict, EncodingContext, from_slice, to_bytes, Type};
98 /// use byteorder::LE;
99 ///
100 /// #[derive(DeserializeDict, SerializeDict, Type, PartialEq, Debug)]
101 /// // `#[zvariant(signature = "a{sv}")]` would be the same.
102 /// #[zvariant(signature = "dict")]
103 /// struct Struct {
104 ///     field1: u16,
105 ///     field2: i64,
106 ///     field3: String,
107 /// }
108 ///
109 /// assert_eq!(Struct::signature(), "a{sv}");
110 /// let s = Struct {
111 ///     field1: 42,
112 ///     field2: i64::max_value(),
113 ///     field3: "hello".to_string(),
114 /// };
115 /// let ctxt = EncodingContext::<LE>::new_dbus(0);
116 /// let encoded = to_bytes(ctxt, &s).unwrap();
117 /// let decoded: Struct = from_slice(&encoded, ctxt).unwrap();
118 /// assert_eq!(decoded, s);
119 /// ```
120 ///
121 /// [`Type`]: https://docs.rs/zvariant/2.10.0/zvariant/trait.Type.html
122 /// [`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html
123 /// [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html
124 /// [serde_repr]: https://crates.io/crates/serde_repr
125 #[proc_macro_derive(Type, attributes(zvariant))]
type_macro_derive(input: TokenStream) -> TokenStream126 pub fn type_macro_derive(input: TokenStream) -> TokenStream {
127     let ast: DeriveInput = syn::parse(input).unwrap();
128     r#type::expand_derive(ast)
129         .unwrap_or_else(|err| err.to_compile_error())
130         .into()
131 }
132 
133 /// Derive macro to add [`Type`] implementation to structs serialized as `a{sv}` type.
134 ///
135 /// # Examples
136 ///
137 /// ```
138 /// use zvariant::{Signature, Type, TypeDict};
139 ///
140 /// #[derive(TypeDict)]
141 /// struct Struct {
142 ///     field: u32,
143 /// }
144 ///
145 /// assert_eq!(Struct::signature(), Signature::from_str_unchecked("a{sv}"));
146 /// ```
147 ///
148 /// [`Type`]: ../zvariant/trait.Type.html
149 #[proc_macro_derive(TypeDict)]
150 #[deprecated(
151     since = "3.1.0",
152     note = "Please use `Type` macro with `#[zvariant(signature = \"dict\")]` attribute instead."
153 )]
type_dict_macro_derive(input: TokenStream) -> TokenStream154 pub fn type_dict_macro_derive(input: TokenStream) -> TokenStream {
155     let ast: DeriveInput = syn::parse(input).unwrap();
156     dict::expand_type_derive(ast)
157         .unwrap_or_else(|err| err.to_compile_error())
158         .into()
159 }
160 
161 /// Adds [`Serialize`] implementation to structs to be serialized as `a{sv}` type.
162 ///
163 /// This macro serializes the deriving struct as a D-Bus dictionary type, where keys are strings and
164 /// values are generic values. Such dictionary types are very commonly used with
165 /// [D-Bus](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties)
166 /// and GVariant.
167 ///
168 /// # Examples
169 ///
170 /// For structs it works just like serde's [`Serialize`] macros:
171 ///
172 /// ```
173 /// use zvariant::{SerializeDict, Type};
174 ///
175 /// #[derive(SerializeDict, Type)]
176 /// #[zvariant(signature = "a{sv}")]
177 /// struct Struct {
178 ///     field1: u16,
179 ///     #[zvariant(rename = "another-name")]
180 ///     field2: i64,
181 ///     optional_field: Option<String>,
182 /// }
183 /// ```
184 ///
185 /// The serialized D-Bus version of `Struct {42, 77, None}`
186 /// will be `{"field1": Value::U16(42), "another-name": Value::I64(77)}`.
187 ///
188 /// [`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html
189 #[proc_macro_derive(SerializeDict, attributes(zvariant))]
serialize_dict_macro_derive(input: TokenStream) -> TokenStream190 pub fn serialize_dict_macro_derive(input: TokenStream) -> TokenStream {
191     let input: DeriveInput = syn::parse(input).unwrap();
192     dict::expand_serialize_derive(input)
193         .unwrap_or_else(|err| err.to_compile_error())
194         .into()
195 }
196 
197 /// Adds [`Deserialize`] implementation to structs to be deserialized from `a{sv}` type.
198 ///
199 /// This macro deserializes a D-Bus dictionary type as a struct, where keys are strings and values
200 /// are generic values. Such dictionary types are very commonly used with
201 /// [D-Bus](https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties)
202 /// and GVariant.
203 ///
204 /// # Examples
205 ///
206 /// For structs it works just like serde's [`Deserialize`] macros:
207 ///
208 /// ```
209 /// use zvariant::{DeserializeDict, Type};
210 ///
211 /// #[derive(DeserializeDict, Type)]
212 /// #[zvariant(signature = "a{sv}")]
213 /// struct Struct {
214 ///     field1: u16,
215 ///     #[zvariant(rename = "another-name")]
216 ///     field2: i64,
217 ///     optional_field: Option<String>,
218 /// }
219 /// ```
220 ///
221 /// The deserialized D-Bus dictionary `{"field1": Value::U16(42), "another-name": Value::I64(77)}`
222 /// will be `Struct {42, 77, None}`.
223 ///
224 /// [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html
225 #[proc_macro_derive(DeserializeDict, attributes(zvariant))]
deserialize_dict_macro_derive(input: TokenStream) -> TokenStream226 pub fn deserialize_dict_macro_derive(input: TokenStream) -> TokenStream {
227     let input: DeriveInput = syn::parse(input).unwrap();
228     dict::expand_deserialize_derive(input)
229         .unwrap_or_else(|err| err.to_compile_error())
230         .into()
231 }
232 
233 /// Implements conversions for your type to/from [`Value`].
234 ///
235 /// Implements `TryFrom<Value>` and `Into<Value>` for your type.
236 ///
237 /// # Examples
238 ///
239 /// Simple owned strutures:
240 ///
241 /// ```
242 /// use std::convert::TryFrom;
243 /// use zvariant::{OwnedObjectPath, OwnedValue, Value};
244 ///
245 /// #[derive(Clone, Value, OwnedValue)]
246 /// struct OwnedStruct {
247 ///     owned_str: String,
248 ///     owned_path: OwnedObjectPath,
249 /// }
250 ///
251 /// let s = OwnedStruct {
252 ///     owned_str: String::from("hi"),
253 ///     owned_path: OwnedObjectPath::try_from("/blah").unwrap(),
254 /// };
255 /// let value = Value::from(s.clone());
256 /// let _ = OwnedStruct::try_from(value).unwrap();
257 /// let value = OwnedValue::from(s);
258 /// let s = OwnedStruct::try_from(value).unwrap();
259 /// assert_eq!(s.owned_str, "hi");
260 /// assert_eq!(s.owned_path.as_str(), "/blah");
261 /// ```
262 ///
263 /// Now for the more exciting case of unowned structures:
264 ///
265 /// ```
266 ///# use std::convert::TryFrom;
267 /// use zvariant::{ObjectPath, Str};
268 ///# use zvariant::{OwnedValue, Value};
269 ///#
270 /// #[derive(Clone, Value, OwnedValue)]
271 /// struct UnownedStruct<'a> {
272 ///     s: Str<'a>,
273 ///     path: ObjectPath<'a>,
274 /// }
275 ///
276 /// let hi = String::from("hi");
277 /// let s = UnownedStruct {
278 ///     s: Str::from(&hi),
279 ///     path: ObjectPath::try_from("/blah").unwrap(),
280 /// };
281 /// let value = Value::from(s.clone());
282 /// let s = UnownedStruct::try_from(value).unwrap();
283 ///
284 /// let value = OwnedValue::from(s);
285 /// let s = UnownedStruct::try_from(value).unwrap();
286 /// assert_eq!(s.s, "hi");
287 /// assert_eq!(s.path, "/blah");
288 /// ```
289 ///
290 /// Generic structures also supported:
291 ///
292 /// ```
293 ///# use std::convert::TryFrom;
294 ///# use zvariant::{OwnedObjectPath, OwnedValue, Value};
295 ///#
296 /// #[derive(Clone, Value, OwnedValue)]
297 /// struct GenericStruct<S, O> {
298 ///     field1: S,
299 ///     field2: O,
300 /// }
301 ///
302 /// let s = GenericStruct {
303 ///     field1: String::from("hi"),
304 ///     field2: OwnedObjectPath::try_from("/blah").unwrap(),
305 /// };
306 /// let value = Value::from(s.clone());
307 /// let _ = GenericStruct::<String, OwnedObjectPath>::try_from(value).unwrap();
308 /// let value = OwnedValue::from(s);
309 /// let s = GenericStruct::<String, OwnedObjectPath>::try_from(value).unwrap();
310 /// assert_eq!(s.field1, "hi");
311 /// assert_eq!(s.field2.as_str(), "/blah");
312 /// ```
313 ///
314 /// Enums also supported but currently only simple ones w/ an integer representation:
315 ///
316 /// ```
317 ///# use std::convert::TryFrom;
318 ///# use zvariant::{OwnedObjectPath, OwnedValue, Value};
319 ///#
320 /// #[derive(Debug, PartialEq, Value, OwnedValue)]
321 /// #[repr(u8)]
322 /// enum Enum {
323 ///     Variant1 = 1,
324 ///     Variant2 = 2,
325 /// }
326 ///
327 /// let value = Value::from(Enum::Variant1);
328 /// let e = Enum::try_from(value).unwrap();
329 /// assert_eq!(e, Enum::Variant1);
330 /// let value = OwnedValue::from(Enum::Variant2);
331 /// let e = Enum::try_from(value).unwrap();
332 /// assert_eq!(e, Enum::Variant2);
333 /// ```
334 ///
335 /// # Dictionary encoding
336 ///
337 /// For treating your type as a dictionary, you can use the `signature = "dict"` attribute. See
338 /// [`Type`] for more details and an example use. Please note that this macro can only handle
339 /// `dict` or `a{sv}` values. All other values will be ignored.
340 ///
341 /// [`Value`]: https://docs.rs/zvariant/2.10.0/zvariant/enum.Value.html
342 /// [`Type`]: derive.Type.html#custom-types
343 #[proc_macro_derive(Value)]
value_macro_derive(input: TokenStream) -> TokenStream344 pub fn value_macro_derive(input: TokenStream) -> TokenStream {
345     let ast: DeriveInput = syn::parse(input).unwrap();
346     value::expand_derive(ast, value::ValueType::Value)
347         .unwrap_or_else(|err| err.to_compile_error())
348         .into()
349 }
350 
351 /// Implements conversions for your type to/from [`OwnedValue`].
352 ///
353 /// Implements `TryFrom<OwnedValue>` and `Into<OwnedValue>` for your type.
354 ///
355 /// See [`Value`] documentation for examples.
356 ///
357 /// [`OwnedValue`]: https://docs.rs/zvariant/2.10.0/zvariant/struct.OwnedValue.html
358 #[proc_macro_derive(OwnedValue)]
owned_value_macro_derive(input: TokenStream) -> TokenStream359 pub fn owned_value_macro_derive(input: TokenStream) -> TokenStream {
360     let ast: DeriveInput = syn::parse(input).unwrap();
361     value::expand_derive(ast, value::ValueType::OwnedValue)
362         .unwrap_or_else(|err| err.to_compile_error())
363         .into()
364 }
365