1 | use proc_macro2::Span; |
2 | use syn::{spanned::Spanned, Meta}; |
3 | |
4 | use crate::{FromMeta, Result}; |
5 | |
6 | /// A meta-item that can be present as a word - with no value - or absent. |
7 | /// |
8 | /// # Defaulting |
9 | /// Like `Option`, `Flag` does not require `#[darling(default)]` to be optional. |
10 | /// If the caller does not include the property, then an absent `Flag` will be included |
11 | /// in the receiver struct. |
12 | /// |
13 | /// # Spans |
14 | /// `Flag` keeps the span where its word was seen. |
15 | /// This enables attaching custom error messages to the word, such as in the case of two |
16 | /// conflicting flags being present. |
17 | /// |
18 | /// # Example |
19 | /// ```ignore |
20 | /// #[derive(FromMeta)] |
21 | /// #[darling(and_then = "Self::not_both" )] |
22 | /// struct Demo { |
23 | /// flag_a: Flag, |
24 | /// flag_b: Flag, |
25 | /// } |
26 | /// |
27 | /// impl Demo { |
28 | /// fn not_both(self) -> Result<Self> { |
29 | /// if self.flag_a.is_present() && self.flag_b.is_present() { |
30 | /// Err(Error::custom("Cannot set flag_a and flag_b" ).with_span(self.flag_b)) |
31 | /// } else { |
32 | /// Ok(self) |
33 | /// } |
34 | /// } |
35 | /// } |
36 | /// ``` |
37 | /// |
38 | /// The above struct would then produce the following error. |
39 | /// |
40 | /// ```ignore |
41 | /// #[example(flag_a, flag_b)] |
42 | /// // ^^^^^^ Cannot set flag_a and flag_b |
43 | /// ``` |
44 | #[derive (Debug, Clone, Copy, Default)] |
45 | pub struct Flag(Option<Span>); |
46 | |
47 | impl Flag { |
48 | /// Creates a new `Flag` which corresponds to the presence of a value. |
49 | pub fn present() -> Self { |
50 | Flag(Some(Span::call_site())) |
51 | } |
52 | |
53 | /// Check if the flag is present. |
54 | pub fn is_present(&self) -> bool { |
55 | self.0.is_some() |
56 | } |
57 | |
58 | #[deprecated (since = "0.14.0" , note = "Use Flag::is_present" )] |
59 | pub fn is_some(&self) -> bool { |
60 | self.is_present() |
61 | } |
62 | } |
63 | |
64 | impl FromMeta for Flag { |
65 | fn from_none() -> Option<Self> { |
66 | Some(Flag(None)) |
67 | } |
68 | |
69 | fn from_meta(mi: &syn::Meta) -> Result<Self> { |
70 | if let Meta::Path(p: &Path) = mi { |
71 | Ok(Flag(Some(p.span()))) |
72 | } else { |
73 | // The implementation for () will produce an error for all non-path meta items; |
74 | // call it to make sure the span behaviors and error messages are the same. |
75 | Err(<()>::from_meta(item:mi).unwrap_err()) |
76 | } |
77 | } |
78 | } |
79 | |
80 | impl Spanned for Flag { |
81 | fn span(&self) -> Span { |
82 | self.0.unwrap_or_else(Span::call_site) |
83 | } |
84 | } |
85 | |
86 | impl From<Flag> for bool { |
87 | fn from(flag: Flag) -> Self { |
88 | flag.is_present() |
89 | } |
90 | } |
91 | |
92 | impl From<bool> for Flag { |
93 | fn from(v: bool) -> Self { |
94 | if v { |
95 | Flag::present() |
96 | } else { |
97 | Flag(None) |
98 | } |
99 | } |
100 | } |
101 | |