1use core::mem::take;
2
3use crate::ast::prelude::*;
4
5use super::Attribute;
6
7#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
9#[non_exhaustive]
10pub enum Item {
11 Use(ast::ItemUse),
13 Fn(ast::ItemFn),
16 Enum(ast::ItemEnum),
18 Struct(ast::ItemStruct),
20 Impl(ast::ItemImpl),
22 Mod(ast::ItemMod),
24 Const(ast::ItemConst),
26 Static(ast::ItemStatic),
28 MacroCall(ast::MacroCall),
30}
31
32impl Item {
33 pub(crate) fn attributes(&self) -> &[ast::Attribute] {
35 match self {
36 Self::Use(item) => &item.attributes,
37 Self::Fn(item) => &item.attributes,
38 Self::Enum(item) => &item.attributes,
39 Self::Struct(item) => &item.attributes,
40 Self::Impl(item) => &item.attributes,
41 Self::Mod(item) => &item.attributes,
42 Self::Const(item) => &item.attributes,
43 Self::Static(item) => &item.attributes,
44 Self::MacroCall(item) => &item.attributes,
45 }
46 }
47 pub(crate) fn attributes_mut(&mut self) -> &mut Vec<ast::Attribute> {
49 match self {
50 Self::Use(item) => &mut item.attributes,
51 Self::Fn(item) => &mut item.attributes,
52 Self::Enum(item) => &mut item.attributes,
53 Self::Struct(item) => &mut item.attributes,
54 Self::Impl(item) => &mut item.attributes,
55 Self::Mod(item) => &mut item.attributes,
56 Self::Const(item) => &mut item.attributes,
57 Self::Static(item) => &mut item.attributes,
58 Self::MacroCall(item) => &mut item.attributes,
59 }
60 }
61
62 pub(crate) fn needs_semi_colon(&self) -> bool {
64 match self {
65 Self::Use(..) => true,
66 Self::Struct(st) => st.needs_semi_colon(),
67 Self::Const(..) => true,
68 Self::Static(..) => true,
69 _ => false,
70 }
71 }
72
73 pub(crate) fn peek_as_item(p: &mut Peeker<'_>) -> bool {
75 match p.nth(0) {
76 K![use] => true,
77 K![enum] => true,
78 K![struct] => true,
79 K![impl] => true,
80 K![async] => matches!(p.nth(1), K![fn]),
81 K![fn] => true,
82 K![mod] => true,
83 K![const] => true,
84 K![static] => true,
85 _ => false,
86 }
87 }
88
89 pub(crate) fn parse_with_meta_path(
91 p: &mut Parser<'_>,
92 mut attributes: Vec<ast::Attribute>,
93 mut visibility: ast::Visibility,
94 path: Option<ast::Path>,
95 ) -> Result<Self> {
96 let item = if let Some(path) = path {
97 Self::MacroCall(ast::MacroCall::parse_with_meta_path(
98 p,
99 take(&mut attributes),
100 path,
101 )?)
102 } else {
103 let mut const_token = p.parse::<Option<T![const]>>()?;
104 let mut static_token = p.parse::<Option<T![static]>>()?;
105 let mut async_token = p.parse::<Option<T![async]>>()?;
106
107 let item = match p.nth(0)? {
108 K![use] => Self::Use(ast::ItemUse::parse_with_meta(
109 p,
110 take(&mut attributes),
111 take(&mut visibility),
112 )?),
113 K![enum] => Self::Enum(ast::ItemEnum::parse_with_meta(
114 p,
115 take(&mut attributes),
116 take(&mut visibility),
117 )?),
118 K![struct] => Self::Struct(ast::ItemStruct::parse_with_meta(
119 p,
120 take(&mut attributes),
121 take(&mut visibility),
122 )?),
123 K![impl] => Self::Impl(ast::ItemImpl::parse_with_attributes(
124 p,
125 take(&mut attributes),
126 )?),
127 K![fn] => Self::Fn(ast::ItemFn::parse_with_meta(
128 p,
129 take(&mut attributes),
130 take(&mut visibility),
131 take(&mut const_token),
132 take(&mut async_token),
133 )?),
134 K![mod] => Self::Mod(ast::ItemMod::parse_with_meta(
135 p,
136 take(&mut attributes),
137 take(&mut visibility),
138 )?),
139 K![ident] => {
140 if let Some(const_token) = const_token.take() {
141 Self::Const(ast::ItemConst::parse_with_meta(
142 p,
143 take(&mut attributes),
144 take(&mut visibility),
145 const_token,
146 )?)
147 } else if let Some(static_token) = static_token.take() {
148 Self::Static(ast::ItemStatic::parse_with_meta(
149 p,
150 take(&mut attributes),
151 take(&mut visibility),
152 static_token,
153 )?)
154 } else {
155 Self::MacroCall(p.parse()?)
156 }
157 }
158 _ => {
159 return Err(compile::Error::expected(
160 p.tok_at(0)?,
161 "`fn`, `mod`, `struct`, `enum`, `use`, or macro call",
162 ))
163 }
164 };
165
166 if let Some(span) = const_token.option_span() {
167 return Err(compile::Error::unsupported(span, "const modifier"));
168 }
169
170 if let Some(span) = static_token.option_span() {
171 return Err(compile::Error::unsupported(span, "static modifier"));
172 }
173
174 if let Some(span) = async_token.option_span() {
175 return Err(compile::Error::unsupported(span, "async modifier"));
176 }
177
178 item
179 };
180
181 if let Some(span) = attributes.option_span() {
182 return Err(compile::Error::unsupported(span, "attribute"));
183 }
184
185 if let Some(span) = visibility.option_span() {
186 return Err(compile::Error::unsupported(span, "visibility modifier"));
187 }
188
189 Ok(item)
190 }
191
192 pub(crate) fn remove_first_attribute(&mut self) -> Option<Attribute> {
194 let attributes = self.attributes_mut();
195
196 if !attributes.is_empty() {
197 return Some(attributes.remove(0));
198 }
199
200 None
201 }
202}
203
204impl Parse for Item {
205 fn parse(p: &mut Parser<'_>) -> Result<Self> {
206 let attributes = p.parse()?;
207 let visibility = p.parse()?;
208 let path = p.parse()?;
209 Self::parse_with_meta_path(p, attributes, visibility, path)
210 }
211}