1use super::{Attribute, Comment, DocString, Ident, LitInt, Prelude, TypeName};
2use crate::Span;
3use crate::error::{
4 DuplicateStructField, DuplicateStructFieldId, InvalidStructFieldId, RecursiveStruct,
5};
6use crate::grammar::Rule;
7use crate::validate::Validate;
8use crate::warning::{BrokenDocLink, NonCamelCaseStruct, NonSnakeCaseStructField};
9use pest::iterators::Pair;
10
11#[derive(Debug, Clone)]
12pub struct StructDef {
13 span: Span,
14 comment: Vec<Comment>,
15 doc: Vec<DocString>,
16 attrs: Vec<Attribute>,
17 name: Ident,
18 fields: Vec<StructField>,
19 fallback: Option<StructFallback>,
20}
21
22impl StructDef {
23 pub(crate) fn parse(pair: Pair<Rule>) -> Self {
24 assert_eq!(pair.as_rule(), Rule::struct_def);
25
26 let span = Span::from_pair(&pair);
27 let mut pairs = pair.into_inner();
28 let mut prelude = Prelude::regular(&mut pairs);
29
30 pairs.next().unwrap(); let pair = pairs.next().unwrap();
33 let name = Ident::parse(&pair);
34
35 pairs.next().unwrap(); let mut fields = Vec::new();
38 let mut fallback = None;
39
40 for pair in pairs {
41 #[expect(clippy::wildcard_enum_match_arm)]
42 match pair.as_rule() {
43 Rule::struct_field => fields.push(StructField::parse(pair)),
44 Rule::struct_fallback => fallback = Some(StructFallback::parse(pair)),
45 Rule::tok_cur_close => break,
46 _ => unreachable!(),
47 }
48 }
49
50 Self {
51 span,
52 comment: prelude.take_comment(),
53 doc: prelude.take_doc(),
54 attrs: prelude.take_attrs(),
55 name,
56 fields,
57 fallback,
58 }
59 }
60
61 pub(crate) fn validate(&self, validate: &mut Validate) {
62 DuplicateStructField::validate(
63 &self.fields,
64 self.fallback.as_ref(),
65 Some(&self.name),
66 validate,
67 );
68
69 BrokenDocLink::validate(&self.doc, validate);
70 DuplicateStructFieldId::validate(&self.fields, Some(&self.name), validate);
71 NonCamelCaseStruct::validate(self, validate);
72 RecursiveStruct::validate(self, validate);
73
74 self.name.validate(true, validate);
75
76 for field in &self.fields {
77 field.validate(validate);
78 }
79
80 if let Some(ref fallback) = self.fallback {
81 fallback.validate(validate);
82 }
83 }
84
85 pub fn span(&self) -> Span {
86 self.span
87 }
88
89 pub fn comment(&self) -> &[Comment] {
90 &self.comment
91 }
92
93 pub fn doc(&self) -> &[DocString] {
94 &self.doc
95 }
96
97 pub fn attributes(&self) -> &[Attribute] {
98 &self.attrs
99 }
100
101 pub fn name(&self) -> &Ident {
102 &self.name
103 }
104
105 pub fn fields(&self) -> &[StructField] {
106 &self.fields
107 }
108
109 pub fn fallback(&self) -> Option<&StructFallback> {
110 self.fallback.as_ref()
111 }
112}
113
114#[derive(Debug, Clone)]
115pub struct InlineStruct {
116 span: Span,
117 kw_span: Span,
118 doc: Vec<DocString>,
119 attrs: Vec<Attribute>,
120 fields: Vec<StructField>,
121 fallback: Option<StructFallback>,
122}
123
124impl InlineStruct {
125 pub(crate) fn parse(pair: Pair<Rule>) -> Self {
126 assert_eq!(pair.as_rule(), Rule::struct_inline);
127
128 let span = Span::from_pair(&pair);
129 let mut pairs = pair.into_inner();
130
131 let pair = pairs.next().unwrap();
132 let kw_span = Span::from_pair(&pair);
133
134 pairs.next().unwrap(); let mut prelude = Prelude::inline(&mut pairs);
137 let mut fields = Vec::new();
138 let mut fallback = None;
139
140 for pair in pairs {
141 #[expect(clippy::wildcard_enum_match_arm)]
142 match pair.as_rule() {
143 Rule::struct_field => fields.push(StructField::parse(pair)),
144 Rule::struct_fallback => fallback = Some(StructFallback::parse(pair)),
145 Rule::tok_cur_close => break,
146 _ => unreachable!(),
147 }
148 }
149
150 Self {
151 span,
152 kw_span,
153 doc: prelude.take_doc(),
154 attrs: prelude.take_attrs(),
155 fields,
156 fallback,
157 }
158 }
159
160 pub(crate) fn validate(&self, validate: &mut Validate) {
161 BrokenDocLink::validate(&self.doc, validate);
162 DuplicateStructField::validate(&self.fields, self.fallback.as_ref(), None, validate);
163 DuplicateStructFieldId::validate(&self.fields, None, validate);
164
165 for field in &self.fields {
166 field.validate(validate);
167 }
168
169 if let Some(ref fallback) = self.fallback {
170 fallback.validate(validate);
171 }
172 }
173
174 pub fn span(&self) -> Span {
175 self.span
176 }
177
178 pub fn keyword_span(&self) -> Span {
179 self.kw_span
180 }
181
182 pub fn doc(&self) -> &[DocString] {
183 &self.doc
184 }
185
186 pub fn attributes(&self) -> &[Attribute] {
187 &self.attrs
188 }
189
190 pub fn fields(&self) -> &[StructField] {
191 &self.fields
192 }
193
194 pub fn fallback(&self) -> Option<&StructFallback> {
195 self.fallback.as_ref()
196 }
197}
198
199#[derive(Debug, Clone)]
200pub struct StructField {
201 span: Span,
202 comment: Vec<Comment>,
203 doc: Vec<DocString>,
204 req: bool,
205 name: Ident,
206 id: LitInt,
207 field_type: TypeName,
208}
209
210impl StructField {
211 fn parse(pair: Pair<Rule>) -> Self {
212 assert_eq!(pair.as_rule(), Rule::struct_field);
213
214 let span = Span::from_pair(&pair);
215 let mut pairs = pair.into_inner();
216 let mut prelude = Prelude::regular(&mut pairs);
217
218 let (req, name) = match pairs.next().map(|pair| (pair.as_rule(), pair)).unwrap() {
219 (Rule::kw_required, _) => (true, Ident::parse(&pairs.next().unwrap())),
220 (Rule::ident, pair) => (false, Ident::parse(&pair)),
221 _ => unreachable!(),
222 };
223
224 pairs.next().unwrap(); let pair = pairs.next().unwrap();
227 let id = LitInt::parse(&pair);
228
229 pairs.next().unwrap(); let pair = pairs.next().unwrap();
232 let field_type = TypeName::parse(pair);
233
234 Self {
235 span,
236 comment: prelude.take_comment(),
237 doc: prelude.take_doc(),
238 req,
239 name,
240 id,
241 field_type,
242 }
243 }
244
245 fn validate(&self, validate: &mut Validate) {
246 BrokenDocLink::validate(&self.doc, validate);
247 InvalidStructFieldId::validate(self, validate);
248 NonSnakeCaseStructField::validate(&self.name, validate);
249
250 self.name.validate(true, validate);
251 self.field_type.validate(false, validate);
252 }
253
254 pub fn span(&self) -> Span {
255 self.span
256 }
257
258 pub fn comment(&self) -> &[Comment] {
259 &self.comment
260 }
261
262 pub fn doc(&self) -> &[DocString] {
263 &self.doc
264 }
265
266 pub fn required(&self) -> bool {
267 self.req
268 }
269
270 pub fn name(&self) -> &Ident {
271 &self.name
272 }
273
274 pub fn id(&self) -> &LitInt {
275 &self.id
276 }
277
278 pub fn field_type(&self) -> &TypeName {
279 &self.field_type
280 }
281}
282
283#[derive(Debug, Clone)]
284pub struct StructFallback {
285 span: Span,
286 comment: Vec<Comment>,
287 doc: Vec<DocString>,
288 name: Ident,
289}
290
291impl StructFallback {
292 pub(crate) fn parse(pair: Pair<Rule>) -> Self {
293 assert_eq!(pair.as_rule(), Rule::struct_fallback);
294
295 let span = Span::from_pair(&pair);
296 let mut pairs = pair.into_inner();
297 let mut prelude = Prelude::regular(&mut pairs);
298
299 Self {
300 span,
301 comment: prelude.take_comment(),
302 doc: prelude.take_doc(),
303 name: Ident::parse(&pairs.next().unwrap()),
304 }
305 }
306
307 pub(crate) fn validate(&self, validate: &mut Validate) {
308 BrokenDocLink::validate(&self.doc, validate);
309 NonSnakeCaseStructField::validate(&self.name, validate);
310
311 self.name.validate(true, validate);
312 }
313
314 pub fn span(&self) -> Span {
315 self.span
316 }
317
318 pub fn comment(&self) -> &[Comment] {
319 &self.comment
320 }
321
322 pub fn doc(&self) -> &[DocString] {
323 &self.doc
324 }
325
326 pub fn name(&self) -> &Ident {
327 &self.name
328 }
329}