|
7 | 7 | use crate::REFLECT_ATTRIBUTE_NAME;
|
8 | 8 | use quote::ToTokens;
|
9 | 9 | use syn::spanned::Spanned;
|
10 |
| -use syn::{Attribute, Meta, NestedMeta}; |
| 10 | +use syn::{Attribute, Lit, Meta, NestedMeta}; |
11 | 11 |
|
12 | 12 | pub(crate) static IGNORE_ATTR: &str = "ignore";
|
| 13 | +pub(crate) static DEFAULT_ATTR: &str = "default"; |
13 | 14 |
|
14 | 15 | /// A container for attributes defined on a field reflected type's field.
|
15 | 16 | #[derive(Default)]
|
16 | 17 | pub(crate) struct ReflectFieldAttr {
|
17 | 18 | /// Determines if this field should be ignored.
|
18 | 19 | pub ignore: bool,
|
| 20 | + /// Sets the default behavior of this field. |
| 21 | + pub default: DefaultBehavior, |
| 22 | +} |
| 23 | + |
| 24 | +/// Controls how the default value is determined for a field. |
| 25 | +pub(crate) enum DefaultBehavior { |
| 26 | + /// Field is required. |
| 27 | + Required, |
| 28 | + /// Field can be defaulted using `Default::default()`. |
| 29 | + Default, |
| 30 | + /// Field can be created using the given function name. |
| 31 | + /// |
| 32 | + /// This assumes the function is in scope, is callable with zero arguments, |
| 33 | + /// and returns the expected type. |
| 34 | + Func(syn::ExprPath), |
| 35 | +} |
| 36 | + |
| 37 | +impl Default for DefaultBehavior { |
| 38 | + fn default() -> Self { |
| 39 | + Self::Required |
| 40 | + } |
19 | 41 | }
|
20 | 42 |
|
21 | 43 | /// Parse all field attributes marked "reflect" (such as `#[reflect(ignore)]`).
|
@@ -50,10 +72,29 @@ fn parse_meta(args: &mut ReflectFieldAttr, meta: &Meta) -> Result<(), syn::Error
|
50 | 72 | args.ignore = true;
|
51 | 73 | Ok(())
|
52 | 74 | }
|
| 75 | + Meta::Path(path) if path.is_ident(DEFAULT_ATTR) => { |
| 76 | + args.default = DefaultBehavior::Default; |
| 77 | + Ok(()) |
| 78 | + } |
53 | 79 | Meta::Path(path) => Err(syn::Error::new(
|
54 | 80 | path.span(),
|
55 | 81 | format!("unknown attribute parameter: {}", path.to_token_stream()),
|
56 | 82 | )),
|
| 83 | + Meta::NameValue(pair) if pair.path.is_ident(DEFAULT_ATTR) => { |
| 84 | + let lit = &pair.lit; |
| 85 | + match lit { |
| 86 | + Lit::Str(lit_str) => { |
| 87 | + args.default = DefaultBehavior::Func(lit_str.parse()?); |
| 88 | + Ok(()) |
| 89 | + } |
| 90 | + err => { |
| 91 | + Err(syn::Error::new( |
| 92 | + err.span(), |
| 93 | + format!("expected a string literal containing the name of a function, but found: {}", err.to_token_stream()), |
| 94 | + )) |
| 95 | + } |
| 96 | + } |
| 97 | + } |
57 | 98 | Meta::NameValue(pair) => {
|
58 | 99 | let path = &pair.path;
|
59 | 100 | Err(syn::Error::new(
|
|
0 commit comments