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