proc_macro_util/
attr.rs

1// from serde_derive
2
3use super::ctxt::Ctxt;
4use proc_macro2::TokenStream;
5use quote::ToTokens;
6
7/// A symbol is a string identifier
8#[derive(Copy, Clone, Debug)]
9pub struct Symbol(pub &'static str);
10impl PartialEq<Symbol> for syn::Ident {
11    fn eq(&self, word: &Symbol) -> bool {
12        self == word.0
13    }
14}
15
16impl<'a> PartialEq<Symbol> for &'a syn::Ident {
17    fn eq(&self, word: &Symbol) -> bool {
18        *self == word.0
19    }
20}
21
22impl PartialEq<Symbol> for syn::Path {
23    fn eq(&self, word: &Symbol) -> bool {
24        self.is_ident(word.0)
25    }
26}
27
28impl<'a> PartialEq<Symbol> for &'a syn::Path {
29    fn eq(&self, word: &Symbol) -> bool {
30        self.is_ident(word.0)
31    }
32}
33
34impl std::fmt::Display for Symbol {
35    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
36        formatter.write_str(self.0)
37    }
38}
39
40/// An attribute identified by a symbol
41pub struct Attr<'c, T> {
42    cx: &'c Ctxt,
43    name: Symbol,
44    tokens: TokenStream,
45    value: Option<T>,
46}
47
48impl<'c, T> Attr<'c, T> {
49    /// Create an attribute without ay value
50    pub fn none(cx: &'c Ctxt, name: Symbol) -> Self {
51        Attr {
52            cx,
53            name,
54            tokens: TokenStream::new(),
55            value: None,
56        }
57    }
58
59    /// Set the value of the attribute
60    pub fn set<A: ToTokens>(&mut self, obj: A, value: T) {
61        let tokens = obj.into_token_stream();
62
63        if self.value.is_some() {
64            self.cx.error_spanned_by(
65                tokens,
66                format!("duplicate composable attribute `{:?}`", self.name),
67            );
68        } else {
69            self.tokens = tokens;
70            self.value = Some(value);
71        }
72    }
73
74    /// Set an optional value of the attribute
75    pub fn set_opt<A: ToTokens>(&mut self, obj: A, value: Option<T>) {
76        if let Some(value) = value {
77            self.set(obj, value);
78        }
79    }
80
81    /// Set oly if the attribute don't have a value
82    pub fn set_if_none(&mut self, value: T) {
83        if self.value.is_none() {
84            self.value = Some(value);
85        }
86    }
87
88    /// Get the current value of the attribute
89    pub fn get(self) -> Option<T> {
90        self.value
91    }
92
93    /// Get the value along with the associatd tokens
94    pub fn get_with_tokens(self) -> Option<(TokenStream, T)> {
95        match self.value {
96            Some(v) => Some((self.tokens, v)),
97            None => None,
98        }
99    }
100}