1use proc_macro2::Span;
2use syn::{spanned::Spanned, Meta};
3
4use 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)]
45pub struct Flag(Option<Span>);
46
47impl 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
64impl 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
80impl Spanned for Flag {
81 fn span(&self) -> Span {
82 self.0.unwrap_or_else(Span::call_site)
83 }
84}
85
86impl From<Flag> for bool {
87 fn from(flag: Flag) -> Self {
88 flag.is_present()
89 }
90}
91
92impl 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