summaryrefslogtreecommitdiffstats
path: root/third_party/rust/darling/examples/fallible_read.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/darling/examples/fallible_read.rs')
-rw-r--r--third_party/rust/darling/examples/fallible_read.rs85
1 files changed, 85 insertions, 0 deletions
diff --git a/third_party/rust/darling/examples/fallible_read.rs b/third_party/rust/darling/examples/fallible_read.rs
new file mode 100644
index 0000000000..850465e82d
--- /dev/null
+++ b/third_party/rust/darling/examples/fallible_read.rs
@@ -0,0 +1,85 @@
+//! 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<T, syn::Meta>` to attempt a recovery in imperative code
+//! 1. Using the `map` darling meta-item to post-process a field before returning
+//! 1. Using the `and_then` darling meta-item to post-process the receiver before returning
+
+use darling::{FromDeriveInput, FromMeta};
+use syn::parse_str;
+
+#[derive(Debug, FromDeriveInput)]
+#[darling(attributes(my_trait), and_then = "MyInputReceiver::autocorrect")]
+pub struct MyInputReceiver {
+ /// This field must be present and a string or else parsing will panic.
+ #[darling(map = "MyInputReceiver::make_string_shouty")]
+ 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 or fail in `and_then`.
+ frequency: darling::Result<i64>,
+
+ /// 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<u64, syn::Meta>,
+}
+
+impl MyInputReceiver {
+ /// This function will be called by `darling` _after_ it's finished parsing the
+ /// `name` field but before initializing `name` with the resulting value. It's
+ /// a good place for transforms that are easiest to express on already-built
+ /// types.
+ fn make_string_shouty(s: String) -> String {
+ s.to_uppercase()
+ }
+
+ /// 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) -> darling::Result<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) => (i64::from_meta(&mi)?).abs() as u64,
+ };
+
+ Ok(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
+ );
+}