• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.span()))
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.
present() -> Self49     pub fn present() -> Self {
50         Flag(Some(Span::call_site()))
51     }
52 
53     /// Check if the flag is present.
is_present(&self) -> bool54     pub fn is_present(&self) -> bool {
55         self.0.is_some()
56     }
57 
58     #[deprecated(since = "0.14.0", note = "Use Flag::is_present")]
is_some(&self) -> bool59     pub fn is_some(&self) -> bool {
60         self.is_present()
61     }
62 
63     /// Get the span of the flag, or [`Span::call_site`] if the flag was not present.
span(&self) -> Span64     pub fn span(&self) -> Span {
65         self.0.unwrap_or_else(Span::call_site)
66     }
67 }
68 
69 impl FromMeta for Flag {
from_none() -> Option<Self>70     fn from_none() -> Option<Self> {
71         Some(Flag(None))
72     }
73 
from_meta(mi: &syn::Meta) -> Result<Self>74     fn from_meta(mi: &syn::Meta) -> Result<Self> {
75         if let Meta::Path(p) = mi {
76             Ok(Flag(Some(p.span())))
77         } else {
78             // The implementation for () will produce an error for all non-path meta items;
79             // call it to make sure the span behaviors and error messages are the same.
80             Err(<()>::from_meta(mi).unwrap_err())
81         }
82     }
83 }
84 
85 impl From<Flag> for bool {
from(flag: Flag) -> Self86     fn from(flag: Flag) -> Self {
87         flag.is_present()
88     }
89 }
90 
91 impl From<bool> for Flag {
from(v: bool) -> Self92     fn from(v: bool) -> Self {
93         if v {
94             Flag::present()
95         } else {
96             Flag(None)
97         }
98     }
99 }
100