1 //! This example demonstrates techniques for performing custom error handling
2 //! in a derive-input receiver.
3 //!
4 //! 1. Using `darling::Result` as a carrier to preserve the error for later display
5 //! 1. Using `Result<T, syn::Meta>` to attempt a recovery in imperative code
6 //! 1. Using the `map` darling meta-item to post-process a field before returning
7 //! 1. Using the `and_then` darling meta-item to post-process the receiver before returning
8 
9 use darling::{FromDeriveInput, FromMeta};
10 use syn::parse_str;
11 
12 #[derive(Debug, FromDeriveInput)]
13 #[darling(attributes(my_trait), and_then = MyInputReceiver::autocorrect)]
14 pub struct MyInputReceiver {
15     /// This field must be present and a string or else parsing will panic.
16     #[darling(map = MyInputReceiver::make_string_shouty)]
17     name: String,
18 
19     /// If this field fails to parse, the struct can still be built; the field
20     /// will contain the error. The consuming struct can then decide if this
21     /// blocks code generation. If so, panic or fail in `and_then`.
22     frequency: darling::Result<i64>,
23 
24     /// If this field fails to parse, the struct can still be built; the field
25     /// will contain an `Err` with the original `syn::Meta`. This can be used
26     /// for alternate parsing attempts before panicking.
27     amplitude: Result<u64, syn::Meta>,
28 }
29 
30 impl MyInputReceiver {
31     /// This function will be called by `darling` _after_ it's finished parsing the
32     /// `name` field but before initializing `name` with the resulting value. It's
33     /// a good place for transforms that are easiest to express on already-built
34     /// types.
make_string_shouty(s: String) -> String35     fn make_string_shouty(s: String) -> String {
36         s.to_uppercase()
37     }
38 
39     /// This function will be called by `darling` _after_ it's finished parsing the
40     /// input but before returning to the caller. This is a good place to initialize
41     /// skipped fields or to perform corrections that don't lend themselves to being
42     /// done elsewhere.
autocorrect(self) -> darling::Result<Self>43     fn autocorrect(self) -> darling::Result<Self> {
44         let Self {
45             name,
46             frequency,
47             amplitude,
48         } = self;
49 
50         // Amplitude doesn't have a sign, so if we received a negative number then
51         // we'll go ahead and make it positive.
52         let amplitude = match amplitude {
53             Ok(amp) => amp,
54             Err(mi) => (i64::from_meta(&mi)?).unsigned_abs(),
55         };
56 
57         Ok(Self {
58             name,
59             frequency,
60             amplitude: Ok(amplitude),
61         })
62     }
63 }
64 
main()65 fn main() {
66     let input = r#"#[derive(MyTrait)]
67 #[my_trait(name="Jon", amplitude = "-1", frequency = 1)]
68 pub struct Foo;"#;
69 
70     let parsed = parse_str(input).unwrap();
71     let receiver = MyInputReceiver::from_derive_input(&parsed).unwrap();
72 
73     println!(
74         r#"
75 INPUT:
76 
77 {}
78 
79 PARSED AS:
80 
81 {:?}
82     "#,
83         input, receiver
84     );
85 }
86