1use super::ctxt::Ctxt;
4use proc_macro2::TokenStream;
5use quote::ToTokens;
6
7#[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
40pub 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 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 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 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 pub fn set_if_none(&mut self, value: T) {
83 if self.value.is_none() {
84 self.value = Some(value);
85 }
86 }
87
88 pub fn get(self) -> Option<T> {
90 self.value
91 }
92
93 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}