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 MacroCall(ast::MacroCall),
28}
29
30impl Item {
31 pub(crate) fn attributes(&self) -> &[ast::Attribute] {
33 match self {
34 Self::Use(item) => &item.attributes,
35 Self::Fn(item) => &item.attributes,
36 Self::Enum(item) => &item.attributes,
37 Self::Struct(item) => &item.attributes,
38 Self::Impl(item) => &item.attributes,
39 Self::Mod(item) => &item.attributes,
40 Self::Const(item) => &item.attributes,
41 Self::MacroCall(item) => &item.attributes,
42 }
43 }
44 pub(crate) fn attributes_mut(&mut self) -> &mut Vec<ast::Attribute> {
46 match self {
47 Self::Use(item) => &mut item.attributes,
48 Self::Fn(item) => &mut item.attributes,
49 Self::Enum(item) => &mut item.attributes,
50 Self::Struct(item) => &mut item.attributes,
51 Self::Impl(item) => &mut item.attributes,
52 Self::Mod(item) => &mut item.attributes,
53 Self::Const(item) => &mut item.attributes,
54 Self::MacroCall(item) => &mut item.attributes,
55 }
56 }
57
58 pub(crate) fn needs_semi_colon(&self) -> bool {
60 match self {
61 Self::Use(..) => true,
62 Self::Struct(st) => st.needs_semi_colon(),
63 Self::Const(..) => true,
64 _ => false,
65 }
66 }
67
68 pub(crate) fn peek_as_item(p: &mut Peeker<'_>) -> bool {
70 match p.nth(0) {
71 K![use] => true,
72 K![enum] => true,
73 K![struct] => true,
74 K![impl] => true,
75 K![async] => matches!(p.nth(1), K![fn]),
76 K![fn] => true,
77 K![mod] => true,
78 K![const] => true,
79 _ => false,
80 }
81 }
82
83 pub(crate) fn parse_with_meta_path(
85 p: &mut Parser<'_>,
86 mut attributes: Vec<ast::Attribute>,
87 mut visibility: ast::Visibility,
88 path: Option<ast::Path>,
89 ) -> Result<Self> {
90 let item = if let Some(path) = path {
91 Self::MacroCall(ast::MacroCall::parse_with_meta_path(
92 p,
93 take(&mut attributes),
94 path,
95 )?)
96 } else {
97 let mut const_token = p.parse::<Option<T![const]>>()?;
98 let mut async_token = p.parse::<Option<T![async]>>()?;
99
100 let item = match p.nth(0)? {
101 K![use] => Self::Use(ast::ItemUse::parse_with_meta(
102 p,
103 take(&mut attributes),
104 take(&mut visibility),
105 )?),
106 K![enum] => Self::Enum(ast::ItemEnum::parse_with_meta(
107 p,
108 take(&mut attributes),
109 take(&mut visibility),
110 )?),
111 K![struct] => Self::Struct(ast::ItemStruct::parse_with_meta(
112 p,
113 take(&mut attributes),
114 take(&mut visibility),
115 )?),
116 K![impl] => Self::Impl(ast::ItemImpl::parse_with_attributes(
117 p,
118 take(&mut attributes),
119 )?),
120 K![fn] => Self::Fn(ast::ItemFn::parse_with_meta(
121 p,
122 take(&mut attributes),
123 take(&mut visibility),
124 take(&mut const_token),
125 take(&mut async_token),
126 )?),
127 K![mod] => Self::Mod(ast::ItemMod::parse_with_meta(
128 p,
129 take(&mut attributes),
130 take(&mut visibility),
131 )?),
132 K![ident] => {
133 if let Some(const_token) = const_token.take() {
134 Self::Const(ast::ItemConst::parse_with_meta(
135 p,
136 take(&mut attributes),
137 take(&mut visibility),
138 const_token,
139 )?)
140 } else {
141 Self::MacroCall(p.parse()?)
142 }
143 }
144 _ => {
145 return Err(compile::Error::expected(
146 p.tok_at(0)?,
147 "`fn`, `mod`, `struct`, `enum`, `use`, or macro call",
148 ))
149 }
150 };
151
152 if let Some(span) = const_token.option_span() {
153 return Err(compile::Error::unsupported(span, "const modifier"));
154 }
155
156 if let Some(span) = async_token.option_span() {
157 return Err(compile::Error::unsupported(span, "async modifier"));
158 }
159
160 item
161 };
162
163 if let Some(span) = attributes.option_span() {
164 return Err(compile::Error::unsupported(span, "attribute"));
165 }
166
167 if let Some(span) = visibility.option_span() {
168 return Err(compile::Error::unsupported(span, "visibility modifier"));
169 }
170
171 Ok(item)
172 }
173
174 pub(crate) fn remove_first_attribute(&mut self) -> Option<Attribute> {
176 let attributes = self.attributes_mut();
177
178 if !attributes.is_empty() {
179 return Some(attributes.remove(0));
180 }
181
182 None
183 }
184}
185
186impl Parse for Item {
187 fn parse(p: &mut Parser<'_>) -> Result<Self> {
188 let attributes = p.parse()?;
189 let visibility = p.parse()?;
190 let path = p.parse()?;
191 Self::parse_with_meta_path(p, attributes, visibility, path)
192 }
193}