1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | mod boxed_derive; |
4 | mod clone; |
5 | mod closure; |
6 | mod derived_properties_attribute; |
7 | mod downgrade_derive; |
8 | mod enum_derive; |
9 | mod error_domain_derive; |
10 | mod flags_attribute; |
11 | mod object_interface_attribute; |
12 | mod object_subclass_attribute; |
13 | mod properties; |
14 | mod shared_boxed_derive; |
15 | mod value_delegate_derive; |
16 | mod variant_derive; |
17 | |
18 | mod utils; |
19 | |
20 | use flags_attribute::AttrInput; |
21 | use proc_macro::TokenStream; |
22 | use proc_macro_error::proc_macro_error ; |
23 | use syn::{parse_macro_input, DeriveInput}; |
24 | use utils::{parse_nested_meta_items_from_stream, NestedMetaItem}; |
25 | |
26 | /// Macro for passing variables as strong or weak references into a closure. |
27 | /// |
28 | /// This macro can be useful in combination with closures, e.g. signal handlers, to reduce the |
29 | /// boilerplate required for passing strong or weak references into the closure. It will |
30 | /// automatically create the new reference and pass it with the same name into the closure. |
31 | /// |
32 | /// If upgrading the weak reference to a strong reference inside the closure is failing, the |
33 | /// closure is immediately returning an optional default return value. If none is provided, `()` is |
34 | /// returned. |
35 | /// |
36 | /// **⚠️ IMPORTANT ⚠️** |
37 | /// |
38 | /// `glib` needs to be in scope, so unless it's one of the direct crate dependencies, you need to |
39 | /// import it because `clone!` is using it. For example: |
40 | /// |
41 | /// ```rust,ignore |
42 | /// use gtk::glib; |
43 | /// ``` |
44 | /// |
45 | /// ### Debugging |
46 | /// |
47 | /// In case something goes wrong inside the `clone!` macro, we use the [`g_debug`] macro. Meaning |
48 | /// that if you want to see these debug messages, you'll have to set the `G_MESSAGES_DEBUG` |
49 | /// environment variable when running your code (either in the code directly or when running the |
50 | /// binary) to either "all" or [`CLONE_MACRO_LOG_DOMAIN`]: |
51 | /// |
52 | /// [`g_debug`]: ../glib/macro.g_debug.html |
53 | /// [`CLONE_MACRO_LOG_DOMAIN`]: ../glib/constant.CLONE_MACRO_LOG_DOMAIN.html |
54 | /// |
55 | /// ```rust,ignore |
56 | /// use glib::CLONE_MACRO_LOG_DOMAIN; |
57 | /// |
58 | /// std::env::set_var("G_MESSAGES_DEBUG" , CLONE_MACRO_LOG_DOMAIN); |
59 | /// std::env::set_var("G_MESSAGES_DEBUG" , "all" ); |
60 | /// ``` |
61 | /// |
62 | /// Or: |
63 | /// |
64 | /// ```bash |
65 | /// $ G_MESSAGES_DEBUG=all ./binary |
66 | /// ``` |
67 | /// |
68 | /// ### Passing a strong reference |
69 | /// |
70 | /// ``` |
71 | /// use glib; |
72 | /// use glib_macros::clone; |
73 | /// use std::rc::Rc; |
74 | /// |
75 | /// let v = Rc::new(1); |
76 | /// let closure = clone!(@strong v => move |x| { |
77 | /// println!("v: {}, x: {}" , v, x); |
78 | /// }); |
79 | /// |
80 | /// closure(2); |
81 | /// ``` |
82 | /// |
83 | /// ### Passing a weak reference |
84 | /// |
85 | /// ``` |
86 | /// use glib; |
87 | /// use glib_macros::clone; |
88 | /// use std::rc::Rc; |
89 | /// |
90 | /// let u = Rc::new(2); |
91 | /// let closure = clone!(@weak u => move |x| { |
92 | /// println!("u: {}, x: {}" , u, x); |
93 | /// }); |
94 | /// |
95 | /// closure(3); |
96 | /// ``` |
97 | /// |
98 | /// #### Allowing a nullable weak reference |
99 | /// |
100 | /// In some cases, even if the weak references can't be retrieved, you might want to still have |
101 | /// your closure called. In this case, you need to use `@weak-allow-none`: |
102 | /// |
103 | /// ``` |
104 | /// use glib; |
105 | /// use glib_macros::clone; |
106 | /// use std::rc::Rc; |
107 | /// |
108 | /// let closure = { |
109 | /// // This `Rc` won't be available in the closure because it's dropped at the end of the |
110 | /// // current block |
111 | /// let u = Rc::new(2); |
112 | /// clone!(@weak-allow-none u => @default-return false, move |x| { |
113 | /// // We need to use a Debug print for `u` because it'll be an `Option`. |
114 | /// println!("u: {:?}, x: {}" , u, x); |
115 | /// true |
116 | /// }) |
117 | /// }; |
118 | /// |
119 | /// assert_eq!(closure(3), true); |
120 | /// ``` |
121 | /// |
122 | /// ### Creating owned values from references (`ToOwned`) |
123 | /// |
124 | /// ``` |
125 | /// use glib; |
126 | /// use glib_macros::clone; |
127 | /// |
128 | /// let v = "123" ; |
129 | /// let closure = clone!(@to-owned v => move |x| { |
130 | /// // v is passed as `String` here |
131 | /// println!("v: {}, x: {}" , v, x); |
132 | /// }); |
133 | /// |
134 | /// closure(2); |
135 | /// ``` |
136 | /// |
137 | /// ### Renaming variables |
138 | /// |
139 | /// ``` |
140 | /// use glib; |
141 | /// use glib_macros::clone; |
142 | /// use std::rc::Rc; |
143 | /// |
144 | /// let v = Rc::new(1); |
145 | /// let u = Rc::new(2); |
146 | /// let closure = clone!(@strong v as y, @weak u => move |x| { |
147 | /// println!("v as y: {}, u: {}, x: {}" , y, u, x); |
148 | /// }); |
149 | /// |
150 | /// closure(3); |
151 | /// ``` |
152 | /// |
153 | /// ### Providing a default return value if upgrading a weak reference fails |
154 | /// |
155 | /// You can do it in two different ways: |
156 | /// |
157 | /// Either by providing the value yourself using `@default-return`: |
158 | /// |
159 | /// ``` |
160 | /// use glib; |
161 | /// use glib_macros::clone; |
162 | /// use std::rc::Rc; |
163 | /// |
164 | /// let v = Rc::new(1); |
165 | /// let closure = clone!(@weak v => @default-return false, move |x| { |
166 | /// println!("v: {}, x: {}" , v, x); |
167 | /// true |
168 | /// }); |
169 | /// |
170 | /// // Drop value so that the weak reference can't be upgraded. |
171 | /// drop(v); |
172 | /// |
173 | /// assert_eq!(closure(2), false); |
174 | /// ``` |
175 | /// |
176 | /// Or by using `@default-panic` (if the value fails to get upgraded, it'll panic): |
177 | /// |
178 | /// ```should_panic |
179 | /// # use glib; |
180 | /// # use glib_macros::clone; |
181 | /// # use std::rc::Rc; |
182 | /// # let v = Rc::new(1); |
183 | /// let closure = clone!(@weak v => @default-panic, move |x| { |
184 | /// println!("v: {}, x: {}" , v, x); |
185 | /// true |
186 | /// }); |
187 | /// # drop(v); |
188 | /// # assert_eq!(closure(2), false); |
189 | /// ``` |
190 | /// |
191 | /// ### Errors |
192 | /// |
193 | /// Here is a list of errors you might encounter: |
194 | /// |
195 | /// **Missing `@weak` or `@strong`**: |
196 | /// |
197 | /// ```compile_fail |
198 | /// # use glib; |
199 | /// # use glib_macros::clone; |
200 | /// # use std::rc::Rc; |
201 | /// let v = Rc::new(1); |
202 | /// |
203 | /// let closure = clone!(v => move |x| println!("v: {}, x: {}" , v, x)); |
204 | /// # drop(v); |
205 | /// # closure(2); |
206 | /// ``` |
207 | /// |
208 | /// **Passing `self` as an argument**: |
209 | /// |
210 | /// ```compile_fail |
211 | /// # use glib; |
212 | /// # use glib_macros::clone; |
213 | /// # use std::rc::Rc; |
214 | /// #[derive(Debug)] |
215 | /// struct Foo; |
216 | /// |
217 | /// impl Foo { |
218 | /// fn foo(&self) { |
219 | /// let closure = clone!(@strong self => move |x| { |
220 | /// println!("self: {:?}" , self); |
221 | /// }); |
222 | /// # closure(2); |
223 | /// } |
224 | /// } |
225 | /// ``` |
226 | /// |
227 | /// If you want to use `self` directly, you'll need to rename it: |
228 | /// |
229 | /// ``` |
230 | /// # use glib; |
231 | /// # use glib_macros::clone; |
232 | /// # use std::rc::Rc; |
233 | /// #[derive(Debug)] |
234 | /// struct Foo; |
235 | /// |
236 | /// impl Foo { |
237 | /// fn foo(&self) { |
238 | /// let closure = clone!(@strong self as this => move |x| { |
239 | /// println!("self: {:?}" , this); |
240 | /// }); |
241 | /// # closure(2); |
242 | /// } |
243 | /// } |
244 | /// ``` |
245 | /// |
246 | /// **Passing fields directly** |
247 | /// |
248 | /// ```compile_fail |
249 | /// # use glib; |
250 | /// # use glib_macros::clone; |
251 | /// # use std::rc::Rc; |
252 | /// #[derive(Debug)] |
253 | /// struct Foo { |
254 | /// v: Rc<usize>, |
255 | /// } |
256 | /// |
257 | /// impl Foo { |
258 | /// fn foo(&self) { |
259 | /// let closure = clone!(@strong self.v => move |x| { |
260 | /// println!("self.v: {:?}" , v); |
261 | /// }); |
262 | /// # closure(2); |
263 | /// } |
264 | /// } |
265 | /// ``` |
266 | /// |
267 | /// You can do it by renaming it: |
268 | /// |
269 | /// ``` |
270 | /// # use glib; |
271 | /// # use glib_macros::clone; |
272 | /// # use std::rc::Rc; |
273 | /// # struct Foo { |
274 | /// # v: Rc<usize>, |
275 | /// # } |
276 | /// impl Foo { |
277 | /// fn foo(&self) { |
278 | /// let closure = clone!(@strong self.v as v => move |x| { |
279 | /// println!("self.v: {}" , v); |
280 | /// }); |
281 | /// # closure(2); |
282 | /// } |
283 | /// } |
284 | /// ``` |
285 | #[proc_macro ] |
286 | #[proc_macro_error ] |
287 | pub fn clone(item: TokenStream) -> TokenStream { |
288 | clone::clone_inner(item) |
289 | } |
290 | |
291 | /// Macro for creating a [`Closure`] object. This is a wrapper around [`Closure::new`] that |
292 | /// automatically type checks its arguments at run-time. |
293 | /// |
294 | /// A `Closure` takes [`Value`] objects as inputs and output. This macro will automatically convert |
295 | /// the inputs to Rust types when invoking its callback, and then will convert the output back to a |
296 | /// `Value`. All inputs must implement the [`FromValue`] trait, and outputs must either implement |
297 | /// the [`ToValue`] trait or be the unit type `()`. Type-checking of inputs is done at run-time; if |
298 | /// incorrect types are passed via [`Closure::invoke`] then the closure will panic. Note that when |
299 | /// passing input types derived from [`Object`] or [`Interface`], you must take care to upcast to |
300 | /// the exact object or interface type that is being received. |
301 | /// |
302 | /// Similarly to [`clone!`](crate::clone!), this macro can be useful in combination with signal |
303 | /// handlers to reduce boilerplate when passing references. Unique to `Closure` objects is the |
304 | /// ability to watch an object using a the `@watch` directive. Only an [`Object`] value can be |
305 | /// passed to `@watch`, and only one object can be watched per closure. When an object is watched, |
306 | /// a weak reference to the object is held in the closure. When the object is destroyed, the |
307 | /// closure will become invalidated: all signal handlers connected to the closure will become |
308 | /// disconnected, and any calls to [`Closure::invoke`] on the closure will be silently ignored. |
309 | /// Internally, this is accomplished using [`Object::watch_closure`] on the watched object. |
310 | /// |
311 | /// The `@weak-allow-none` and `@strong` captures are also supported and behave the same as in |
312 | /// [`clone!`](crate::clone!), as is aliasing captures with the `as` keyword. Notably, these |
313 | /// captures are able to reference `Rc` and `Arc` values in addition to `Object` values. |
314 | /// |
315 | /// [`Closure`]: ../glib/closure/struct.Closure.html |
316 | /// [`Closure::new`]: ../glib/closure/struct.Closure.html#method.new |
317 | /// [`Closure::new_local`]: ../glib/closure/struct.Closure.html#method.new_local |
318 | /// [`Closure::invoke`]: ../glib/closure/struct.Closure.html#method.invoke |
319 | /// [`Value`]: ../glib/value/struct.Value.html |
320 | /// [`FromValue`]: ../glib/value/trait.FromValue.html |
321 | /// [`ToValue`]: ../glib/value/trait.ToValue.html |
322 | /// [`Interface`]: ../glib/object/struct.Interface.html |
323 | /// [`Object`]: ../glib/object/struct.Object.html |
324 | /// [`Object::watch_closure`]: ../glib/object/trait.ObjectExt.html#tymethod.watch_closure |
325 | /// **⚠️ IMPORTANT ⚠️** |
326 | /// |
327 | /// `glib` needs to be in scope, so unless it's one of the direct crate dependencies, you need to |
328 | /// import it because `closure!` is using it. For example: |
329 | /// |
330 | /// ```rust,ignore |
331 | /// use gtk::glib; |
332 | /// ``` |
333 | /// |
334 | /// ### Using as a closure object |
335 | /// |
336 | /// ``` |
337 | /// use glib_macros::closure; |
338 | /// |
339 | /// let concat_str = closure!(|s: &str| s.to_owned() + " World" ); |
340 | /// let result = concat_str.invoke::<String>(&[&"Hello" ]); |
341 | /// assert_eq!(result, "Hello World" ); |
342 | /// ``` |
343 | /// |
344 | /// ### Connecting to a signal |
345 | /// |
346 | /// For wrapping closures that can't be sent across threads, the |
347 | /// [`closure_local!`](crate::closure_local!) macro can be used. It has the same syntax as |
348 | /// `closure!`, but instead uses [`Closure::new_local`] internally. |
349 | /// |
350 | /// ``` |
351 | /// use glib; |
352 | /// use glib::prelude::*; |
353 | /// use glib_macros::closure_local; |
354 | /// |
355 | /// let obj = glib::Object::new::<glib::Object>(); |
356 | /// obj.connect_closure( |
357 | /// "notify" , false, |
358 | /// closure_local!(|_obj: glib::Object, pspec: glib::ParamSpec| { |
359 | /// println!("property notify: {}" , pspec.name()); |
360 | /// })); |
361 | /// ``` |
362 | /// |
363 | /// ### Object Watching |
364 | /// |
365 | /// ``` |
366 | /// use glib; |
367 | /// use glib::prelude::*; |
368 | /// use glib_macros::closure_local; |
369 | /// |
370 | /// let closure = { |
371 | /// let obj = glib::Object::new::<glib::Object>(); |
372 | /// let closure = closure_local!(@watch obj => move || { |
373 | /// obj.type_().name() |
374 | /// }); |
375 | /// assert_eq!(closure.invoke::<String>(&[]), "GObject" ); |
376 | /// closure |
377 | /// }; |
378 | /// // `obj` is dropped, closure invalidated so it always does nothing and returns None |
379 | /// closure.invoke::<()>(&[]); |
380 | /// ``` |
381 | /// |
382 | /// `@watch` has special behavior when connected to a signal: |
383 | /// |
384 | /// ``` |
385 | /// use glib; |
386 | /// use glib::prelude::*; |
387 | /// use glib_macros::closure_local; |
388 | /// |
389 | /// let obj = glib::Object::new::<glib::Object>(); |
390 | /// { |
391 | /// let other = glib::Object::new::<glib::Object>(); |
392 | /// obj.connect_closure( |
393 | /// "notify" , false, |
394 | /// closure_local!(@watch other as b => move |a: glib::Object, pspec: glib::ParamSpec| { |
395 | /// let value = a.property_value(pspec.name()); |
396 | /// b.set_property(pspec.name(), &value); |
397 | /// })); |
398 | /// // The signal handler will disconnect automatically at the end of this |
399 | /// // block when `other` is dropped. |
400 | /// } |
401 | /// ``` |
402 | /// |
403 | /// ### Weak and Strong References |
404 | /// |
405 | /// ``` |
406 | /// use glib; |
407 | /// use glib::prelude::*; |
408 | /// use glib_macros::closure; |
409 | /// use std::sync::Arc; |
410 | /// |
411 | /// let closure = { |
412 | /// let a = Arc::new(String::from("Hello" )); |
413 | /// let b = Arc::new(String::from("World" )); |
414 | /// let c = "!" ; |
415 | /// let closure = closure!(@strong a, @weak-allow-none b, @to-owned c => move || { |
416 | /// // `a` is Arc<String>, `b` is Option<Arc<String>>, `c` is a `String` |
417 | /// format!("{} {}{}" , a, b.as_ref().map(|b| b.as_str()).unwrap_or_else(|| "Moon" ), c) |
418 | /// }); |
419 | /// assert_eq!(closure.invoke::<String>(&[]), "Hello World!" ); |
420 | /// closure |
421 | /// }; |
422 | /// // `a`, `c` still kept alive, `b` is dropped |
423 | /// assert_eq!(closure.invoke::<String>(&[]), "Hello Moon!" ); |
424 | /// ``` |
425 | #[proc_macro ] |
426 | #[proc_macro_error ] |
427 | pub fn closure(item: TokenStream) -> TokenStream { |
428 | closure::closure_inner(input:item, constructor:"new" ) |
429 | } |
430 | |
431 | /// The same as [`closure!`](crate::closure!) but uses [`Closure::new_local`] as a constructor. |
432 | /// This is useful for closures which can't be sent across threads. See the documentation of |
433 | /// [`closure!`](crate::closure!) for details. |
434 | /// |
435 | /// [`Closure::new_local`]: ../glib/closure/struct.Closure.html#method.new_local |
436 | #[proc_macro ] |
437 | #[proc_macro_error ] |
438 | pub fn closure_local(item: TokenStream) -> TokenStream { |
439 | closure::closure_inner(input:item, constructor:"new_local" ) |
440 | } |
441 | |
442 | /// Derive macro for register a rust enum in the glib type system and derive the |
443 | /// the [`glib::Value`] traits. |
444 | /// |
445 | /// # Example |
446 | /// |
447 | /// ``` |
448 | /// use glib::prelude::*; |
449 | /// use glib::subclass::prelude::*; |
450 | /// |
451 | /// #[derive(Debug, Copy, Clone, PartialEq, Eq, glib::Enum)] |
452 | /// #[enum_type(name = "MyEnum" )] |
453 | /// enum MyEnum { |
454 | /// Val, |
455 | /// #[enum_value(name = "My Val" )] |
456 | /// ValWithCustomName, |
457 | /// #[enum_value(name = "My Other Val" , nick = "other" )] |
458 | /// ValWithCustomNameAndNick, |
459 | /// } |
460 | /// ``` |
461 | /// |
462 | /// [`glib::Value`]: ../glib/value/struct.Value.html |
463 | #[proc_macro_derive (Enum, attributes(enum_type, enum_value))] |
464 | #[proc_macro_error ] |
465 | pub fn enum_derive(input: TokenStream) -> TokenStream { |
466 | let input: DeriveInput = parse_macro_input!(input as DeriveInput); |
467 | let gen: TokenStream = enum_derive::impl_enum(&input); |
468 | gen.into() |
469 | } |
470 | |
471 | /// Attribute macro for defining flags using the `bitflags` crate. |
472 | /// This macro will also define a `GFlags::type_` function and |
473 | /// the [`glib::Value`] traits. |
474 | /// |
475 | /// The expected `GType` name has to be passed as macro attribute. |
476 | /// The name and nick of each flag can also be optionally defined. |
477 | /// Default name is the flag identifier in CamelCase and default nick |
478 | /// is the identifier in kebab-case. |
479 | /// Combined flags should not be registered with the `GType` system |
480 | /// and so needs to be tagged with the `#[flags_value(skip)]` attribute. |
481 | /// |
482 | /// # Example |
483 | /// |
484 | /// ``` |
485 | /// use glib::prelude::*; |
486 | /// use glib::subclass::prelude::*; |
487 | /// |
488 | /// #[glib::flags(name = "MyFlags" )] |
489 | /// enum MyFlags { |
490 | /// #[flags_value(name = "Flag A" , nick = "nick-a" )] |
491 | /// A = 0b00000001, |
492 | /// #[flags_value(name = "Flag B" )] |
493 | /// B = 0b00000010, |
494 | /// #[flags_value(skip)] |
495 | /// AB = Self::A.bits() | Self::B.bits(), |
496 | /// C = 0b00000100, |
497 | /// } |
498 | /// ``` |
499 | /// |
500 | /// [`glib::Value`]: ../glib/value/struct.Value.html |
501 | #[proc_macro_attribute ] |
502 | #[proc_macro_error ] |
503 | pub fn flags (attr: TokenStream, item: TokenStream) -> TokenStream { |
504 | let mut name: NestedMetaItem = NestedMetaItemNestedMetaItem::<syn::LitStr>::new(name:"name" ) |
505 | .required() |
506 | .value_required(); |
507 | |
508 | if let Err(e: Error) = parse_nested_meta_items_from_stream(input:attr.into(), &mut [&mut name]) { |
509 | return e.to_compile_error().into(); |
510 | } |
511 | |
512 | let attr_meta: AttrInput = AttrInput { |
513 | enum_name: name.value.unwrap(), |
514 | }; |
515 | let input: DeriveInput = parse_macro_input!(item as DeriveInput); |
516 | let gen: TokenStream = flags_attribute::impl_flags(attrs:attr_meta, &input); |
517 | gen.into() |
518 | } |
519 | |
520 | /// Derive macro for defining a GLib error domain and its associated |
521 | /// [`ErrorDomain`] trait. |
522 | /// |
523 | /// # Example |
524 | /// |
525 | /// ``` |
526 | /// use glib::prelude::*; |
527 | /// use glib::subclass::prelude::*; |
528 | /// |
529 | /// #[derive(Debug, Copy, Clone, glib::ErrorDomain)] |
530 | /// #[error_domain(name = "ex-foo" )] |
531 | /// enum Foo { |
532 | /// Blah, |
533 | /// Baaz, |
534 | /// } |
535 | /// ``` |
536 | /// |
537 | /// [`ErrorDomain`]: ../glib/error/trait.ErrorDomain.html |
538 | #[proc_macro_derive (ErrorDomain, attributes(error_domain))] |
539 | #[proc_macro_error ] |
540 | pub fn error_domain_derive(input: TokenStream) -> TokenStream { |
541 | let input: DeriveInput = parse_macro_input!(input as DeriveInput); |
542 | let gen: TokenStream = error_domain_derive::impl_error_domain(&input); |
543 | gen.into() |
544 | } |
545 | |
546 | /// Derive macro for defining a [`BoxedType`]`::type_` function and |
547 | /// the [`glib::Value`] traits. Optionally, the type can be marked as |
548 | /// `nullable` to get an implemention of `glib::value::ToValueOptional`. |
549 | /// |
550 | /// # Example |
551 | /// |
552 | /// ``` |
553 | /// use glib::prelude::*; |
554 | /// use glib::subclass::prelude::*; |
555 | /// |
556 | /// #[derive(Clone, Debug, PartialEq, Eq, glib::Boxed)] |
557 | /// #[boxed_type(name = "MyBoxed" )] |
558 | /// struct MyBoxed(String); |
559 | /// |
560 | /// #[derive(Clone, Debug, PartialEq, Eq, glib::Boxed)] |
561 | /// #[boxed_type(name = "MyNullableBoxed" , nullable)] |
562 | /// struct MyNullableBoxed(String); |
563 | /// ``` |
564 | /// |
565 | /// [`BoxedType`]: ../glib/subclass/boxed/trait.BoxedType.html |
566 | /// [`glib::Value`]: ../glib/value/struct.Value.html |
567 | #[proc_macro_derive (Boxed, attributes(boxed_type))] |
568 | #[proc_macro_error ] |
569 | pub fn boxed_derive(input: TokenStream) -> TokenStream { |
570 | let input: DeriveInput = parse_macro_input!(input as DeriveInput); |
571 | let gen: TokenStream = boxed_derive::impl_boxed(&input); |
572 | gen.into() |
573 | } |
574 | |
575 | /// Derive macro for defining a [`SharedType`]`::get_type` function and |
576 | /// the [`glib::Value`] traits. Optionally, the type can be marked as |
577 | /// `nullable` to get an implemention of `glib::value::ToValueOptional`. |
578 | /// |
579 | /// # Example |
580 | /// |
581 | /// ``` |
582 | /// use glib::prelude::*; |
583 | /// use glib::subclass::prelude::*; |
584 | /// |
585 | /// #[derive(Clone, Debug, PartialEq, Eq)] |
586 | /// struct MySharedInner { |
587 | /// foo: String, |
588 | /// } |
589 | /// |
590 | /// #[derive(Clone, Debug, PartialEq, Eq, glib::SharedBoxed)] |
591 | /// #[shared_boxed_type(name = "MySharedBoxed" )] |
592 | /// struct MySharedBoxed(std::sync::Arc<MySharedInner>); |
593 | /// |
594 | /// #[derive(Clone, Debug, PartialEq, Eq, glib::SharedBoxed)] |
595 | /// #[shared_boxed_type(name = "MyNullableSharedBoxed" , nullable)] |
596 | /// struct MyNullableSharedBoxed(std::sync::Arc<MySharedInner>); |
597 | /// ``` |
598 | /// |
599 | /// [`SharedType`]: ../glib/subclass/shared/trait.SharedType.html |
600 | /// [`glib::Value`]: ../glib/value/struct.Value.html |
601 | #[proc_macro_derive (SharedBoxed, attributes(shared_boxed_type))] |
602 | #[proc_macro_error ] |
603 | pub fn shared_boxed_derive(input: TokenStream) -> TokenStream { |
604 | let input: DeriveInput = parse_macro_input!(input as DeriveInput); |
605 | let gen: TokenStream = shared_boxed_derive::impl_shared_boxed(&input); |
606 | gen.into() |
607 | } |
608 | |
609 | /// Macro for boilerplate of [`ObjectSubclass`] implementations. |
610 | /// |
611 | /// This adds implementations for the `type_data()` and `type_()` methods, |
612 | /// which should probably never be defined differently. |
613 | /// |
614 | /// It provides default values for the `Instance`, `Class`, and `Interfaces` |
615 | /// type parameters. If these are present, the macro will use the provided value |
616 | /// instead of the default. |
617 | /// |
618 | /// Usually the defaults for `Instance` and `Class` will work. `Interfaces` is |
619 | /// necessary for types that implement interfaces. |
620 | /// |
621 | /// ```ignore |
622 | /// type Instance = glib::subclass::basic::InstanceStruct<Self>; |
623 | /// type Class = glib::subclass::basic::ClassStruct<Self>; |
624 | /// type Interfaces = (); |
625 | /// ``` |
626 | /// |
627 | /// If no `new()` or `with_class()` method is provide, the macro adds a `new()` |
628 | /// implementation calling `Default::default()`. So the type needs to implement |
629 | /// `Default`, or this should be overridden. |
630 | /// |
631 | /// ```ignore |
632 | /// fn new() -> Self { |
633 | /// Default::default() |
634 | /// } |
635 | /// ``` |
636 | /// |
637 | /// [`ObjectSubclass`]: ../glib/subclass/types/trait.ObjectSubclass.html |
638 | #[proc_macro_attribute ] |
639 | #[proc_macro_error ] |
640 | pub fn object_subclass (_attr: TokenStream, item: TokenStream) -> TokenStream { |
641 | use proc_macro_error::abort_call_site; |
642 | match syn::parse::<syn::ItemImpl>(tokens:item) { |
643 | Ok(input: ItemImpl) => object_subclass_attribute::impl_object_subclass(&input).into(), |
644 | Err(_) => abort_call_site!(object_subclass_attribute::WRONG_PLACE_MSG), |
645 | } |
646 | } |
647 | |
648 | /// Macro for boilerplate of [`ObjectInterface`] implementations. |
649 | /// |
650 | /// This adds implementations for the `get_type()` method, which should probably never be defined |
651 | /// differently. |
652 | /// |
653 | /// It provides default values for the `Prerequisites` type parameter. If this present, the macro |
654 | /// will use the provided value instead of the default. |
655 | /// |
656 | /// `Prerequisites` is interfaces for types that require a specific base class or interfaces. |
657 | /// |
658 | /// ```ignore |
659 | /// type Prerequisites = (); |
660 | /// ``` |
661 | /// |
662 | /// [`ObjectInterface`]: ../glib/subclass/interface/trait.ObjectInterface.html |
663 | #[proc_macro_attribute ] |
664 | #[proc_macro_error ] |
665 | pub fn object_interface (_attr: TokenStream, item: TokenStream) -> TokenStream { |
666 | use proc_macro_error::abort_call_site; |
667 | match syn::parse::<syn::ItemImpl>(tokens:item) { |
668 | Ok(input: ItemImpl) => object_interface_attribute::impl_object_interface(&input).into(), |
669 | Err(_) => abort_call_site!(object_interface_attribute::WRONG_PLACE_MSG), |
670 | } |
671 | } |
672 | |
673 | /// Macro for deriving implementations of [`glib::clone::Downgrade`] and |
674 | /// [`glib::clone::Upgrade`] traits and a weak type. |
675 | /// |
676 | /// # Examples |
677 | /// |
678 | /// ## New Type Idiom |
679 | /// |
680 | /// ```rust,ignore |
681 | /// #[derive(glib::Downgrade)] |
682 | /// pub struct FancyLabel(gtk::Label); |
683 | /// |
684 | /// impl FancyLabel { |
685 | /// pub fn new(label: &str) -> Self { |
686 | /// Self(gtk::LabelBuilder::new().label(label).build()) |
687 | /// } |
688 | /// |
689 | /// pub fn flip(&self) { |
690 | /// self.0.set_angle(180.0 - self.0.angle()); |
691 | /// } |
692 | /// } |
693 | /// |
694 | /// let fancy_label = FancyLabel::new("Look at me!" ); |
695 | /// let button = gtk::ButtonBuilder::new().label("Click me!" ).build(); |
696 | /// button.connect_clicked(clone!(@weak fancy_label => move || fancy_label.flip())); |
697 | /// ``` |
698 | /// |
699 | /// ## Generic New Type |
700 | /// |
701 | /// ```rust,ignore |
702 | /// #[derive(glib::Downgrade)] |
703 | /// pub struct TypedEntry<T>(gtk::Entry, std::marker::PhantomData<T>); |
704 | /// |
705 | /// impl<T: ToString + FromStr> for TypedEntry<T> { |
706 | /// // ... |
707 | /// } |
708 | /// ``` |
709 | /// |
710 | /// ## Structures and Enums |
711 | /// |
712 | /// ```rust,ignore |
713 | /// #[derive(Clone, glib::Downgrade)] |
714 | /// pub struct ControlButtons { |
715 | /// pub up: gtk::Button, |
716 | /// pub down: gtk::Button, |
717 | /// pub left: gtk::Button, |
718 | /// pub right: gtk::Button, |
719 | /// } |
720 | /// |
721 | /// #[derive(Clone, glib::Downgrade)] |
722 | /// pub enum DirectionButton { |
723 | /// Left(gtk::Button), |
724 | /// Right(gtk::Button), |
725 | /// Up(gtk::Button), |
726 | /// Down(gtk::Button), |
727 | /// } |
728 | /// ``` |
729 | /// |
730 | /// [`glib::clone::Downgrade`]: ../glib/clone/trait.Downgrade.html |
731 | /// [`glib::clone::Upgrade`]: ../glib/clone/trait.Upgrade.html |
732 | #[proc_macro_derive (Downgrade)] |
733 | pub fn downgrade(input: TokenStream) -> TokenStream { |
734 | let input: DeriveInput = parse_macro_input!(input as DeriveInput); |
735 | downgrade_derive::impl_downgrade(input) |
736 | } |
737 | |
738 | /// Derive macro for serializing/deserializing custom structs/enums as [`glib::Variant`]s. |
739 | /// |
740 | /// # Example |
741 | /// |
742 | /// ``` |
743 | /// use glib::prelude::*; |
744 | /// |
745 | /// #[derive(Debug, PartialEq, Eq, glib::Variant)] |
746 | /// struct Foo { |
747 | /// some_string: String, |
748 | /// some_int: i32, |
749 | /// } |
750 | /// |
751 | /// let v = Foo { some_string: String::from("bar" ), some_int: 1 }; |
752 | /// let var = v.to_variant(); |
753 | /// assert_eq!(var.get::<Foo>(), Some(v)); |
754 | /// ``` |
755 | /// |
756 | /// When storing `Vec`s of fixed size types it is a good idea to wrap these in |
757 | /// `glib::FixedSizeVariantArray` as serialization/deserialization will be more efficient. |
758 | /// |
759 | /// # Example |
760 | /// |
761 | /// ``` |
762 | /// use glib::prelude::*; |
763 | /// |
764 | /// #[derive(Debug, PartialEq, Eq, glib::Variant)] |
765 | /// struct Foo { |
766 | /// some_vec: glib::FixedSizeVariantArray<Vec<u32>, u32>, |
767 | /// some_int: i32, |
768 | /// } |
769 | /// |
770 | /// let v = Foo { some_vec: vec![1u32, 2u32].into(), some_int: 1 }; |
771 | /// let var = v.to_variant(); |
772 | /// assert_eq!(var.get::<Foo>(), Some(v)); |
773 | /// ``` |
774 | /// |
775 | /// Enums are serialized as a tuple `(sv)` with the first value as a [kebab case] string for the |
776 | /// enum variant, or just `s` if this is a C-style enum. Some additional attributes are supported |
777 | /// for enums: |
778 | /// - `#[variant_enum(repr)]` to serialize the enum variant as an integer type instead of `s`. The |
779 | /// `#[repr]` attribute must also be specified on the enum with a sized integer type, and the type |
780 | /// must implement `Copy`. |
781 | /// - `#[variant_enum(enum)]` uses [`EnumClass`] to serialize/deserialize as nicks. Meant for use |
782 | /// with [`glib::Enum`](Enum). |
783 | /// - `#[variant_enum(flags)]` uses [`FlagsClass`] to serialize/deserialize as nicks. Meant for use |
784 | /// with [`glib::flags`](macro@flags). |
785 | /// - `#[variant_enum(enum, repr)]` serializes as `i32`. Meant for use with [`glib::Enum`](Enum). |
786 | /// The type must also implement `Copy`. |
787 | /// - `#[variant_enum(flags, repr)]` serializes as `u32`. Meant for use with |
788 | /// [`glib::flags`](macro@flags). |
789 | /// |
790 | /// # Example |
791 | /// |
792 | /// ``` |
793 | /// use glib::prelude::*; |
794 | /// |
795 | /// #[derive(Debug, PartialEq, Eq, glib::Variant)] |
796 | /// enum Foo { |
797 | /// MyA, |
798 | /// MyB(i32), |
799 | /// MyC { some_int: u32, some_string: String } |
800 | /// } |
801 | /// |
802 | /// let v = Foo::MyC { some_int: 1, some_string: String::from("bar" ) }; |
803 | /// let var = v.to_variant(); |
804 | /// assert_eq!(var.child_value(0).str(), Some("my-c" )); |
805 | /// assert_eq!(var.get::<Foo>(), Some(v)); |
806 | /// |
807 | /// #[derive(Debug, Copy, Clone, PartialEq, Eq, glib::Variant)] |
808 | /// #[variant_enum(repr)] |
809 | /// #[repr(u8)] |
810 | /// enum Bar { |
811 | /// A, |
812 | /// B = 3, |
813 | /// C = 7 |
814 | /// } |
815 | /// |
816 | /// let v = Bar::B; |
817 | /// let var = v.to_variant(); |
818 | /// assert_eq!(var.get::<u8>(), Some(3)); |
819 | /// assert_eq!(var.get::<Bar>(), Some(v)); |
820 | /// |
821 | /// #[derive(Debug, Copy, Clone, PartialEq, Eq, glib::Enum, glib::Variant)] |
822 | /// #[variant_enum(enum)] |
823 | /// #[enum_type(name = "MyEnum" )] |
824 | /// enum MyEnum { |
825 | /// Val, |
826 | /// #[enum_value(name = "My Val" )] |
827 | /// ValWithCustomName, |
828 | /// #[enum_value(name = "My Other Val" , nick = "other" )] |
829 | /// ValWithCustomNameAndNick, |
830 | /// } |
831 | /// |
832 | /// let v = MyEnum::ValWithCustomNameAndNick; |
833 | /// let var = v.to_variant(); |
834 | /// assert_eq!(var.str(), Some("other" )); |
835 | /// assert_eq!(var.get::<MyEnum>(), Some(v)); |
836 | /// ``` |
837 | /// |
838 | /// [`glib::Variant`]: ../glib/variant/struct.Variant.html |
839 | /// [`EnumClass`]: ../glib/struct.EnumClass.html |
840 | /// [`FlagsClass`]: ../glib/struct.FlagsClass.html |
841 | /// [kebab case]: https://docs.rs/heck/0.4.0/heck/trait.ToKebabCase.html |
842 | #[proc_macro_derive (Variant, attributes(variant_enum))] |
843 | #[proc_macro_error ] |
844 | pub fn variant_derive(input: TokenStream) -> TokenStream { |
845 | let input: DeriveInput = parse_macro_input!(input as DeriveInput); |
846 | variant_derive::impl_variant(input) |
847 | } |
848 | #[proc_macro ] |
849 | pub fn cstr_bytes(item: TokenStream) -> TokenStream { |
850 | syn::parse::Parser::parse2( |
851 | |stream: syn::parse::ParseStream<'_>| { |
852 | let literal = stream.parse::<syn::LitStr>()?; |
853 | stream.parse::<syn::parse::Nothing>()?; |
854 | let bytes = std::ffi::CString::new(literal.value()) |
855 | .map_err(|e| syn::Error::new_spanned(&literal, format!(" {e}" )))? |
856 | .into_bytes_with_nul(); |
857 | let bytes = proc_macro2::Literal::byte_string(&bytes); |
858 | Ok(quote::quote! { #bytes }.into()) |
859 | }, |
860 | item.into(), |
861 | ) |
862 | .unwrap_or_else(|e: Error| e.into_compile_error().into()) |
863 | } |
864 | |
865 | /// This macro enables you to derive object properties in a quick way. |
866 | /// |
867 | /// # Supported `#[property]` attributes |
868 | /// | Attribute | Description | Default | Example | |
869 | /// | --- | --- | --- | --- | |
870 | /// | `name = "literal"` | The name of the property | field ident where `_` (leading and trailing `_` are trimmed) is replaced into `-` | `#[property(name = "prop-name")]` | |
871 | /// | `type = expr` | The type of the property | inferred | `#[property(type = i32)]` | |
872 | /// | `get [= expr]` | Specify that the property is readable and use `PropertyGet::get` [or optionally set a custom internal getter] | | `#[property(get)]`, `#[property(get = get_prop)]`, or `[property(get = \|_\| 2)]` | |
873 | /// | `set [= expr]` | Specify that the property is writable and use `PropertySet::set` [or optionally set a custom internal setter] | | `#[property(set)]`, `#[property(set = set_prop)]`, or `[property(set = \|_, val\| {})]` | |
874 | /// | `override_class = expr` | The type of class of which to override the property from | | `#[property(override_class = SomeClass)]` | |
875 | /// | `override_interface = expr` | The type of interface of which to override the property from | | `#[property(override_interface = SomeInterface)]` | |
876 | /// | `nullable` | Whether to use `Option<T>` in the generated setter method | | `#[property(nullable)]` | |
877 | /// | `member = ident` | Field of the nested type where property is retrieved and set | | `#[property(member = author)]` | |
878 | /// | `construct_only` | Specify that the property is construct only. This will not generate a public setter and only allow the property to be set during object construction. The use of a custom internal setter is supported. | | `#[property(get, construct_only)]` or `#[property(get, set = set_prop, construct_only)]` | |
879 | /// | `builder(<required-params>)[.ident]*` | Used to input required params or add optional Param Spec builder fields | | `#[property(builder(SomeEnum::default()))]`, `#[builder().default_value(1).minimum(0).maximum(5)]`, etc. | |
880 | /// | `default` | Sets the `default_value` field of the Param Spec builder | | `#[property(default = 1)]` | |
881 | /// | `<optional-pspec-builder-fields> = expr` | Used to add optional Param Spec builder fields | | `#[property(minimum = 0)` , `#[property(minimum = 0, maximum = 1)]`, etc. | |
882 | /// | `<optional-pspec-builder-fields>` | Used to add optional Param Spec builder fields | | `#[property(explicit_notify)]` , `#[property(construct_only)]`, etc. | |
883 | /// |
884 | /// ## Using Rust keywords as property names |
885 | /// You might hit a roadblock when declaring properties with this macro because you want to use a name that happens to be a Rust keyword. This may happen with names like `loop`, which is a pretty common name when creating things like animation handlers. |
886 | /// To use those names, you can make use of the raw identifier feature of Rust. Simply prefix the identifier name with `r#` in the struct declaration. Internally, those `r#`s are stripped so you can use its expected name in [`ObjectExt::property`] or within GtkBuilder template files. |
887 | /// |
888 | /// # Generated methods |
889 | /// The following methods are generated on the wrapper type specified on `#[properties(wrapper_type = ...)]`: |
890 | /// * `$property()`, when the property is readable |
891 | /// * `set_$property()`, when the property is writable and not construct-only |
892 | /// * `connect_$property_notify()` |
893 | /// * `notify_$property()` |
894 | /// |
895 | /// ## Extension trait |
896 | /// You can choose to move the method definitions to a trait by using `#[properties(wrapper_type = super::MyType, ext_trait = MyTypePropertiesExt)]`. |
897 | /// The trait name is optional, and defaults to `MyTypePropertiesExt`, where `MyType` is extracted from the wrapper type. |
898 | /// Note: The trait is defined in the same module where the `#[derive(Properties)]` call happens, and is implemented on the wrapper type. |
899 | /// |
900 | /// Notice: You can't reimplement the generated methods on the wrapper type, unless you move them to a trait. |
901 | /// You can change the behavior of the generated getter/setter methods by using a custom internal getter/setter. |
902 | /// |
903 | /// # Internal getters and setters |
904 | /// By default, they are generated for you. However, you can use a custom getter/setter |
905 | /// by assigning an expression to `get`/`set` `#[property]` attributes: `#[property(get = |_| 2, set)]` or `#[property(get, set = custom_setter_func)]`. |
906 | /// |
907 | /// # Supported types |
908 | /// Every type implementing the trait `Property` is supported. |
909 | /// The type `Option<T>` is supported as a property only if `Option<T>` implements `ToValueOptional`. |
910 | /// Optional types also require the `nullable` attribute: without it, the generated setter on the wrapper type |
911 | /// will take `T` instead of `Option<T>`, preventing the user from ever calling the setter with a `None` value. |
912 | /// |
913 | /// ## Adding support for custom types |
914 | /// ### Types wrapping an existing `T: glib::value::ToValue + glib::HasParamSpec` |
915 | /// If you have declared a newtype as |
916 | /// ```rust |
917 | /// struct MyInt(i32); |
918 | /// ``` |
919 | /// you can use it as a property by deriving `glib::ValueDelegate`. |
920 | /// |
921 | /// ### Types with inner mutability |
922 | /// The trait `glib::Property` must be implemented. |
923 | /// The traits `PropertyGet` and `PropertySet` should be implemented to enable the Properties macro |
924 | /// to generate a default internal getter/setter. |
925 | /// If possible, implementing `PropertySetNested` is preferred over `PropertySet`, because it |
926 | /// enables this macro to access the contained type and provide access to its fields, |
927 | /// using the `member = $structfield` syntax. |
928 | /// |
929 | /// ### Types without `glib::HasParamSpec` |
930 | /// If you have encountered a type `T: glib::value::ToValue`, inside the `gtk-rs` crate, which doesn't implement `HasParamSpec`, |
931 | /// then it's a bug and you should report it. |
932 | /// If you need to support a `ToValue` type with a `ParamSpec` not provided by `gtk-rs`, then you need to |
933 | /// implement `glib::HasParamSpec` on that type. |
934 | /// |
935 | /// # Example |
936 | /// ``` |
937 | /// use std::cell::RefCell; |
938 | /// use glib::prelude::*; |
939 | /// use glib::subclass::prelude::*; |
940 | /// use glib_macros::Properties; |
941 | /// |
942 | /// #[derive(Default, Clone)] |
943 | /// struct Author { |
944 | /// name: String, |
945 | /// nick: String, |
946 | /// } |
947 | /// |
948 | /// pub mod imp { |
949 | /// use std::rc::Rc; |
950 | /// |
951 | /// use super::*; |
952 | /// |
953 | /// #[derive(Properties, Default)] |
954 | /// #[properties(wrapper_type = super::Foo)] |
955 | /// pub struct Foo { |
956 | /// #[property(get, set = Self::set_fizz)] |
957 | /// fizz: RefCell<String>, |
958 | /// #[property(name = "author-name" , get, set, type = String, member = name)] |
959 | /// #[property(name = "author-nick" , get, set, type = String, member = nick)] |
960 | /// author: RefCell<Author>, |
961 | /// #[property(get, set, explicit_notify, lax_validation)] |
962 | /// custom_flags: RefCell<String>, |
963 | /// #[property(get, set, minimum = 0, maximum = 3)] |
964 | /// numeric_builder: RefCell<u32>, |
965 | /// #[property(get, set, builder('c' ))] |
966 | /// builder_with_required_param: RefCell<char>, |
967 | /// #[property(get, set, nullable)] |
968 | /// optional: RefCell<Option<String>>, |
969 | /// #[property(get, set)] |
970 | /// smart_pointer: Rc<RefCell<String>>, |
971 | /// } |
972 | /// |
973 | /// #[glib::derived_properties] |
974 | /// impl ObjectImpl for Foo {} |
975 | /// |
976 | /// #[glib::object_subclass] |
977 | /// impl ObjectSubclass for Foo { |
978 | /// const NAME: &'static str = "MyFoo" ; |
979 | /// type Type = super::Foo; |
980 | /// } |
981 | /// |
982 | /// impl Foo { |
983 | /// fn set_fizz(&self, value: String) { |
984 | /// *self.fizz.borrow_mut() = format!("custom set: {}" , value); |
985 | /// } |
986 | /// } |
987 | /// } |
988 | /// |
989 | /// glib::wrapper! { |
990 | /// pub struct Foo(ObjectSubclass<imp::Foo>); |
991 | /// } |
992 | /// |
993 | /// fn main() { |
994 | /// let myfoo: Foo = glib::object::Object::new(); |
995 | /// |
996 | /// myfoo.set_fizz("test value" ); |
997 | /// assert_eq!(myfoo.fizz(), "custom set: test value" .to_string()); |
998 | /// } |
999 | /// ``` |
1000 | #[allow (clippy::needless_doctest_main)] |
1001 | #[proc_macro_derive (Properties, attributes(properties, property))] |
1002 | pub fn derive_props(input: TokenStream) -> TokenStream { |
1003 | let input: PropsMacroInput = parse_macro_input!(input as properties::PropsMacroInput); |
1004 | properties::impl_derive_props(input) |
1005 | } |
1006 | |
1007 | /// When applied to `ObjectImpl` |
1008 | /// ```ignore |
1009 | /// #[glib::derived_properties] |
1010 | /// impl ObjectImpl for CustomObject |
1011 | /// ``` |
1012 | /// this macro generates |
1013 | /// ```ignore |
1014 | /// impl ObjectImpl for CustomObject { |
1015 | /// fn properties() -> &'static [glib::ParamSpec] { |
1016 | /// Self::derived_properties() |
1017 | /// } |
1018 | /// fn set_property(&self, id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { |
1019 | /// self.derived_set_property(id, value, pspec) |
1020 | /// } |
1021 | /// fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value { |
1022 | /// self.derived_property(id, pspec) |
1023 | /// } |
1024 | /// } |
1025 | /// ``` |
1026 | #[proc_macro_attribute ] |
1027 | #[proc_macro_error ] |
1028 | pub fn derived_properties (_attr: TokenStream, item: TokenStream) -> TokenStream { |
1029 | use proc_macro_error::abort_call_site; |
1030 | match syn::parse::<syn::ItemImpl>(tokens:item) { |
1031 | Ok(input: ItemImpl) => derived_properties_attribute::impl_derived_properties(&input).into(), |
1032 | Err(_) => abort_call_site!(derived_properties_attribute::WRONG_PLACE_MSG), |
1033 | } |
1034 | } |
1035 | |
1036 | /// # Example |
1037 | /// ``` |
1038 | /// use glib::prelude::*; |
1039 | /// use glib::ValueDelegate; |
1040 | /// |
1041 | /// #[derive(ValueDelegate, Debug, PartialEq)] |
1042 | /// struct MyInt(i32); |
1043 | /// |
1044 | /// let myv = MyInt(2); |
1045 | /// let convertedv = myv.to_value(); |
1046 | /// assert_eq!(convertedv.get::<MyInt>(), Ok(myv)); |
1047 | /// |
1048 | /// |
1049 | /// #[derive(ValueDelegate, Debug, PartialEq)] |
1050 | /// #[value_delegate(from = u32)] |
1051 | /// enum MyEnum { |
1052 | /// Zero, |
1053 | /// NotZero(u32) |
1054 | /// } |
1055 | /// |
1056 | /// impl From<u32> for MyEnum { |
1057 | /// fn from(v: u32) -> Self { |
1058 | /// match v { |
1059 | /// 0 => MyEnum::Zero, |
1060 | /// x => MyEnum::NotZero(x) |
1061 | /// } |
1062 | /// } |
1063 | /// } |
1064 | /// impl<'a> From<&'a MyEnum> for u32 { |
1065 | /// fn from(v: &'a MyEnum) -> Self { |
1066 | /// match v { |
1067 | /// MyEnum::Zero => 0, |
1068 | /// MyEnum::NotZero(x) => *x |
1069 | /// } |
1070 | /// } |
1071 | /// } |
1072 | /// impl From<MyEnum> for u32 { |
1073 | /// fn from(v: MyEnum) -> Self { |
1074 | /// match v { |
1075 | /// MyEnum::Zero => 0, |
1076 | /// MyEnum::NotZero(x) => x |
1077 | /// } |
1078 | /// } |
1079 | /// } |
1080 | /// |
1081 | /// let myv = MyEnum::NotZero(34); |
1082 | /// let convertedv = myv.to_value(); |
1083 | /// assert_eq!(convertedv.get::<MyEnum>(), Ok(myv)); |
1084 | /// |
1085 | /// |
1086 | /// // If you want your type to be usable inside an `Option`, you can derive `ToValueOptional` |
1087 | /// // by adding `nullable` as follows |
1088 | /// #[derive(ValueDelegate, Debug, PartialEq)] |
1089 | /// #[value_delegate(nullable)] |
1090 | /// struct MyString(String); |
1091 | /// |
1092 | /// let myv = Some(MyString("Hello world" .to_string())); |
1093 | /// let convertedv = myv.to_value(); |
1094 | /// assert_eq!(convertedv.get::<Option<MyString>>(), Ok(myv)); |
1095 | /// let convertedv = None::<MyString>.to_value(); |
1096 | /// assert_eq!(convertedv.get::<Option<MyString>>(), Ok(None::<MyString>)); |
1097 | /// ``` |
1098 | #[proc_macro_derive (ValueDelegate, attributes(value_delegate))] |
1099 | pub fn derive_value_delegate(input: TokenStream) -> TokenStream { |
1100 | let input: ValueDelegateInput = parse_macro_input!(input as value_delegate_derive::ValueDelegateInput); |
1101 | value_delegate_derive::impl_value_delegate(input).unwrap() |
1102 | } |
1103 | |