//! This example demonstrates techniques for performing custom error handling //! in a derive-input receiver. //! //! 1. Using `darling::Result` as a carrier to preserve the error for later display //! 1. Using `Result` to attempt a recovery in imperative code //! 1. Using the `map` darling meta-item to post-process the receiver before returning. #[macro_use] extern crate darling; extern crate syn; use darling::{FromDeriveInput, FromMeta}; use syn::parse_str; #[derive(Debug, FromDeriveInput)] #[darling(attributes(my_trait), map = "MyInputReceiver::autocorrect")] pub struct MyInputReceiver { /// This field must be present and a string or else parsing will panic. name: String, /// If this field fails to parse, the struct can still be built; the field /// will contain the error. The consuming struct can then decide if this /// blocks code generation. If so, panic. Otherwise, recover and proceed. frequency: darling::Result, /// If this field fails to parse, the struct can still be built; the field /// will contain an `Err` with the original `syn::Meta`. This can be used /// for alternate parsing attempts before panicking. amplitude: Result, } impl MyInputReceiver { /// This function will be called by `darling` _after_ it's finished parsing the /// input but before returning to the caller. This is a good place to initialize /// skipped fields or to perform corrections that don't lend themselves to being /// done elsewhere. fn autocorrect(self) -> Self { let Self { name, frequency, amplitude, } = self; // Amplitude doesn't have a sign, so if we received a negative number then // we'll go ahead and make it positive. let amplitude = match amplitude { Ok(amp) => amp, Err(mi) => { let val: i64 = if let Ok(v) = FromMeta::from_meta(&mi) { v } else { panic!(format!("amplitude should have been an integer")) }; val.abs() as u64 } }; Self { name, frequency, amplitude: Ok(amplitude), } } } fn main() { let input = r#"#[derive(MyTrait)] #[my_trait(name="Jon", amplitude = "-1", frequency = "1")] pub struct Foo;"#; let parsed = parse_str(input).unwrap(); let receiver = MyInputReceiver::from_derive_input(&parsed).unwrap(); println!( r#" INPUT: {} PARSED AS: {:?} "#, input, receiver ); }