macroific_attr_parse/value_syntax.rs
1use syn::parse::{Parse, ParseBuffer, ParseStream};
2use syn::{parenthesized, Token};
3
4/// Syntax used for providing a value
5#[derive(Copy, Clone, Eq, PartialEq, Debug)]
6pub enum ValueSyntax {
7 /// `= contents`
8 Eq,
9
10 /// `(contents)`
11 Paren,
12}
13
14impl ValueSyntax {
15 /// Returns `true` if the syntax is [`Eq`](ValueSyntax::Eq).
16 ///
17 /// # Example
18 ///
19 /// ```
20 /// # use macroific_attr_parse::ValueSyntax;
21 /// #
22 /// assert!(ValueSyntax::Eq.is_eq());
23 /// assert!(!ValueSyntax::Paren.is_eq());
24 /// ```
25 #[inline]
26 #[must_use]
27 pub const fn is_eq(self) -> bool {
28 matches!(self, Self::Eq)
29 }
30
31 /// Returns `true` if the syntax is [`Paren`](ValueSyntax::Paren).
32 ///
33 /// # Example
34 ///
35 /// ```
36 /// # use macroific_attr_parse::ValueSyntax;
37 /// #
38 /// assert!(ValueSyntax::Paren.is_paren());
39 /// assert!(!ValueSyntax::Eq.is_paren());
40 /// ```
41 #[inline]
42 #[must_use]
43 pub const fn is_paren(self) -> bool {
44 matches!(self, Self::Paren)
45 }
46
47 /// Peek the stream **without moving the cursor** and attempt to construct self based on the
48 /// next token.
49 ///
50 /// # Example
51 ///
52 /// ```
53 /// # use macroific_attr_parse::ValueSyntax;
54 /// # use syn::parse::{ParseStream, Parse};
55 /// # use proc_macro2::TokenStream;
56 /// # use quote::quote;
57 /// #
58 /// struct Foo {
59 /// peek: Option<ValueSyntax>,
60 /// rest: TokenStream,
61 /// }
62 ///
63 /// impl Parse for Foo {
64 /// fn parse(input: ParseStream) -> syn::Result<Self> {
65 /// let peek = ValueSyntax::from_stream(input);
66 /// let rest = input.parse()?;
67 ///
68 /// Ok(Self { peek, rest })
69 /// }
70 /// }
71 ///
72 /// let v: Foo = syn::parse2(quote!(= 123)).unwrap();
73 /// assert_eq!(v.peek, Some(ValueSyntax::Eq));
74 /// assert_eq!(v.rest.to_string(), "= 123");
75 ///
76 /// let v: Foo = syn::parse2(quote!((456))).unwrap();
77 /// assert_eq!(v.peek, Some(ValueSyntax::Paren));
78 /// assert_eq!(v.rest.to_string(), "(456)");
79 ///
80 /// let v: Foo = syn::parse2(quote!(none)).unwrap();
81 /// assert_eq!(v.peek, None);
82 /// assert_eq!(v.rest.to_string(), "none");
83 /// ```
84 pub fn from_stream(parse: ParseStream) -> Option<Self> {
85 if parse.peek(Token![=]) {
86 Some(Self::Eq)
87 } else if parse.peek(syn::token::Paren) {
88 Some(Self::Paren)
89 } else {
90 None
91 }
92 }
93
94 /// Parse whatever tokens need to be parsed based on the resolved syntax.
95 /// Returns a `ParseBuffer` you should continue parsing if the syntax is
96 /// [`Paren`](ValueSyntax::Paren).
97 ///
98 /// # Example
99 ///
100 /// ```
101 /// # use macroific_attr_parse::ValueSyntax;
102 /// # use syn::parse::{ParseStream, Parse};
103 /// # use quote::quote;
104 /// #
105 /// /// `=` implementation
106 /// struct Wrapper1(syn::LitStr);
107 /// impl Parse for Wrapper1 {
108 /// fn parse(input: ParseStream) -> syn::Result<Self> {
109 /// let inner = ValueSyntax::Eq.parse_token(input)?;
110 /// assert!(inner.is_none());
111 /// Ok(Self(input.parse()?))
112 /// }
113 /// }
114 ///
115 /// /// `(value)` implementation
116 /// struct Wrapper2(syn::LitStr);
117 /// impl Parse for Wrapper2 {
118 /// fn parse(input: ParseStream) -> syn::Result<Self> {
119 /// let inner = ValueSyntax::Paren.parse_token(input)?.expect("expected inner buffer");
120 /// Ok(Self(inner.parse()?))
121 /// }
122 /// }
123 ///
124 /// let v: Wrapper1 = syn::parse2(quote!(= "foo")).unwrap();
125 /// assert_eq!(v.0.value(), "foo");
126 ///
127 /// let v: Wrapper2 = syn::parse2(quote!(("bar"))).unwrap();
128 /// assert_eq!(v.0.value(), "bar");
129 /// ```
130 pub fn parse_token(self, input: ParseStream) -> syn::Result<Option<ParseBuffer>> {
131 match self {
132 Self::Eq => {
133 input.parse::<Token![=]>()?;
134 Ok(None)
135 }
136 Self::Paren => {
137 let content;
138 parenthesized!(content in input);
139 Ok(Some(content))
140 }
141 }
142 }
143
144 /// Parse whatever tokens need to be parsed based on the resolved syntax and
145 /// then parse the referenced value as `P`.
146 ///
147 /// # Example
148 ///
149 /// ```
150 /// # use macroific_attr_parse::ValueSyntax;
151 /// # use syn::parse::{ParseStream, Parse};
152 /// # use quote::quote;
153 /// #
154 /// /// `=` implementation
155 /// struct Wrapper1(syn::LitStr);
156 /// impl Parse for Wrapper1 {
157 /// fn parse(input: ParseStream) -> syn::Result<Self> {
158 /// Ok(Self(ValueSyntax::Eq.parse(input)?))
159 /// }
160 /// }
161 ///
162 /// /// `(value)` implementation
163 /// struct Wrapper2(syn::LitStr);
164 /// impl Parse for Wrapper2 {
165 /// fn parse(input: ParseStream) -> syn::Result<Self> {
166 /// Ok(Self(ValueSyntax::Paren.parse(input)?))
167 /// }
168 /// }
169 ///
170 /// let v: Wrapper1 = syn::parse2(quote!(= "foo")).unwrap();
171 /// assert_eq!(v.0.value(), "foo");
172 ///
173 /// let v: Wrapper2 = syn::parse2(quote!(("bar"))).unwrap();
174 /// assert_eq!(v.0.value(), "bar");
175 /// ```
176 pub fn parse<P: Parse>(self, input: ParseStream) -> syn::Result<P> {
177 if let Some(inner) = self.parse_token(input)? {
178 inner.parse()
179 } else {
180 input.parse()
181 }
182 }
183}