Skip to main content

virtue_next/parse/
body.rs

1use super::attributes::AttributeLocation;
2use super::{Attribute, Visibility, utils::*};
3use crate::prelude::{Delimiter, Ident, Literal, Span, TokenTree};
4use crate::{Error, Result};
5use std::iter::Peekable;
6
7/// The body of a struct
8#[derive(Debug)]
9pub struct StructBody {
10    /// The fields of this struct, `None` if this struct has no fields
11    pub fields: Option<Fields>,
12}
13
14impl StructBody {
15    pub(crate) fn take(input: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Result<Self> {
16        match input.peek() {
17            Some(TokenTree::Group(_)) => {}
18            Some(TokenTree::Punct(p)) if p.as_char() == ';' => {
19                return Ok(StructBody { fields: None });
20            }
21            token => return Error::wrong_token(token, "group or punct"),
22        }
23        let group = assume_group(input.next());
24        let mut stream = group.stream().into_iter().peekable();
25        let fields = match group.delimiter() {
26            Delimiter::Brace => {
27                let fields = UnnamedField::parse_with_name(&mut stream)?;
28                Some(Fields::Struct(fields))
29            }
30            Delimiter::Parenthesis => {
31                let fields = UnnamedField::parse(&mut stream)?;
32                Some(Fields::Tuple(fields))
33            }
34            found => {
35                return Err(Error::InvalidRustSyntax {
36                    span: group.span(),
37                    expected: format!("brace or parenthesis, found {:?}", found),
38                });
39            }
40        };
41        Ok(StructBody { fields })
42    }
43}
44
45#[test]
46fn test_struct_body_take() {
47    use crate::token_stream;
48
49    let stream = &mut token_stream(
50        "struct Foo { pub bar: u8, pub(crate) baz: u32, bla: Vec<Box<dyn Future<Output = ()>>> }",
51    );
52    let (data_type, ident) = super::DataType::take(stream).unwrap();
53    assert_eq!(data_type, super::DataType::Struct);
54    assert_eq!(ident, "Foo");
55    let body = StructBody::take(stream).unwrap();
56    let fields = body.fields.as_ref().unwrap();
57
58    assert_eq!(fields.len(), 3);
59    let (ident, field) = fields.get(0).unwrap();
60    assert_eq!(ident.unwrap(), "bar");
61    assert_eq!(field.vis, Visibility::Pub);
62    assert_eq!(field.type_string(), "u8");
63
64    let (ident, field) = fields.get(1).unwrap();
65    assert_eq!(ident.unwrap(), "baz");
66    assert_eq!(field.vis, Visibility::Pub);
67    assert_eq!(field.type_string(), "u32");
68
69    let (ident, field) = fields.get(2).unwrap();
70    assert_eq!(ident.unwrap(), "bla");
71    assert_eq!(field.vis, Visibility::Default);
72    assert_eq!(field.type_string(), "Vec<Box<dynFuture<Output=()>>>");
73
74    let stream = &mut token_stream(
75        "struct Foo ( pub u8, pub(crate) u32, Vec<Box<dyn Future<Output = ()>>> )",
76    );
77    let (data_type, ident) = super::DataType::take(stream).unwrap();
78    assert_eq!(data_type, super::DataType::Struct);
79    assert_eq!(ident, "Foo");
80    let body = StructBody::take(stream).unwrap();
81    let fields = body.fields.as_ref().unwrap();
82
83    assert_eq!(fields.len(), 3);
84
85    let (ident, field) = fields.get(0).unwrap();
86    assert!(ident.is_none());
87    assert_eq!(field.vis, Visibility::Pub);
88    assert_eq!(field.type_string(), "u8");
89
90    let (ident, field) = fields.get(1).unwrap();
91    assert!(ident.is_none());
92    assert_eq!(field.vis, Visibility::Pub);
93    assert_eq!(field.type_string(), "u32");
94
95    let (ident, field) = fields.get(2).unwrap();
96    assert!(ident.is_none());
97    assert_eq!(field.vis, Visibility::Default);
98    assert_eq!(field.type_string(), "Vec<Box<dynFuture<Output=()>>>");
99
100    let stream = &mut token_stream("struct Foo;");
101    let (data_type, ident) = super::DataType::take(stream).unwrap();
102    assert_eq!(data_type, super::DataType::Struct);
103    assert_eq!(ident, "Foo");
104    let body = StructBody::take(stream).unwrap();
105    assert!(body.fields.is_none());
106
107    let stream = &mut token_stream("struct Foo {}");
108    let (data_type, ident) = super::DataType::take(stream).unwrap();
109    assert_eq!(data_type, super::DataType::Struct);
110    assert_eq!(ident, "Foo");
111    let body = StructBody::take(stream).unwrap();
112    if let Some(Fields::Struct(v)) = body.fields {
113        assert!(v.is_empty());
114    } else {
115        panic!("wrong fields {:?}", body.fields);
116    }
117
118    let stream = &mut token_stream("struct Foo ()");
119    let (data_type, ident) = super::DataType::take(stream).unwrap();
120    assert_eq!(data_type, super::DataType::Struct);
121    assert_eq!(ident, "Foo");
122    let body = StructBody::take(stream).unwrap();
123    if let Some(Fields::Tuple(v)) = body.fields {
124        assert!(v.is_empty());
125    } else {
126        panic!("wrong fields {:?}", body.fields);
127    }
128}
129
130#[test]
131fn issue_77() {
132    // https://github.com/bincode-org/virtue/issues/77
133    use crate::token_stream;
134
135    let stream = &mut token_stream("struct Test(pub [u8; 32])");
136    let (data_type, ident) = super::DataType::take(stream).unwrap();
137    assert_eq!(data_type, super::DataType::Struct);
138    assert_eq!(ident, "Test");
139    let body = StructBody::take(stream).unwrap();
140    let fields = body.fields.unwrap();
141    let Fields::Tuple(t) = fields else {
142        panic!("Fields is not a tuple")
143    };
144    assert_eq!(t.len(), 1);
145    assert_eq!(t[0].r#type[0].to_string(), "[u8 ; 32]");
146
147    let stream = &mut token_stream("struct Foo(pub (u8, ))");
148    let (data_type, ident) = super::DataType::take(stream).unwrap();
149    assert_eq!(data_type, super::DataType::Struct);
150    assert_eq!(ident, "Foo");
151    let body = StructBody::take(stream).unwrap();
152    let fields = body.fields.unwrap();
153    let Fields::Tuple(t) = fields else {
154        panic!("Fields is not a tuple")
155    };
156    assert_eq!(t.len(), 1);
157    assert_eq!(t[0].r#type[0].to_string(), "(u8 ,)");
158}
159
160/// The body of an enum
161#[derive(Debug)]
162pub struct EnumBody {
163    /// The enum's variants
164    pub variants: Vec<EnumVariant>,
165}
166
167impl EnumBody {
168    pub(crate) fn take(input: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Result<Self> {
169        match input.peek() {
170            Some(TokenTree::Group(_)) => {}
171            Some(TokenTree::Punct(p)) if p.as_char() == ';' => {
172                return Ok(EnumBody {
173                    variants: Vec::new(),
174                });
175            }
176            token => return Error::wrong_token(token, "group or ;"),
177        }
178        let group = assume_group(input.next());
179        let mut variants = Vec::new();
180        let mut variant_stream = group.stream().into_iter().peekable();
181        let stream = &mut variant_stream;
182        while stream.peek().is_some() {
183            let attributes = Attribute::try_take(AttributeLocation::Variant, stream)?;
184            let ident = match super::utils::consume_ident(stream) {
185                Some(ident) => ident,
186                None => Error::wrong_token(stream.peek(), "ident")?,
187            };
188
189            let mut fields = None;
190            let mut value = None;
191
192            if let Some(TokenTree::Group(_)) = stream.peek() {
193                let group = assume_group(stream.next());
194                let mut inner_stream = group.stream().into_iter().peekable();
195                let stream_ref = &mut inner_stream;
196                match group.delimiter() {
197                    Delimiter::Brace => {
198                        fields = Some(Fields::Struct(UnnamedField::parse_with_name(stream_ref)?));
199                    }
200                    Delimiter::Parenthesis => {
201                        fields = Some(Fields::Tuple(UnnamedField::parse(stream_ref)?));
202                    }
203                    delim => {
204                        return Err(Error::InvalidRustSyntax {
205                            span: group.span(),
206                            expected: format!("Brace or parenthesis, found {:?}", delim),
207                        });
208                    }
209                }
210            }
211            match stream.peek() {
212                Some(TokenTree::Punct(p)) if p.as_char() == '=' => {
213                    assume_punct(stream.next(), '=');
214
215                    let first_val_token = stream.next(); // Bind #1
216                    match first_val_token {
217                        Some(TokenTree::Literal(lit)) => {
218                            value = Some(lit);
219                        }
220                        Some(TokenTree::Punct(p)) if p.as_char() == '-' => {
221                            let second_val_token = stream.next(); // Bind #2
222                            match second_val_token {
223                                Some(TokenTree::Literal(lit)) => {
224                                    match lit.to_string().parse::<i64>() {
225                                        Ok(val) => value = Some(Literal::i64_unsuffixed(-val)),
226                                        Err(_) => {
227                                            return Err(Error::custom_at(
228                                                "parse::<i64> failed",
229                                                lit.span(),
230                                            ));
231                                        }
232                                    };
233                                }
234                                token => return Error::wrong_token(token.as_ref(), "literal"),
235                            }
236                        }
237                        token => return Error::wrong_token(token.as_ref(), "literal"),
238                    }
239                }
240                Some(TokenTree::Punct(p)) if p.as_char() == ',' => {
241                    // next field
242                }
243                None => {
244                    // group done
245                }
246                token => return Error::wrong_token(token, "group, comma or ="),
247            }
248
249            consume_punct_if(stream, ',');
250
251            variants.push(EnumVariant {
252                name: ident,
253                fields,
254                value,
255                attributes,
256            });
257        }
258
259        Ok(EnumBody { variants })
260    }
261}
262
263#[test]
264fn test_enum_body_take() {
265    use crate::token_stream;
266
267    let stream = &mut token_stream("enum Foo { }");
268    let (data_type, ident) = super::DataType::take(stream).unwrap();
269    assert_eq!(data_type, super::DataType::Enum);
270    assert_eq!(ident, "Foo");
271    let body = EnumBody::take(stream).unwrap();
272    assert!(body.variants.is_empty());
273
274    let stream = &mut token_stream("enum Foo { Bar, Baz(u8), Blah { a: u32, b: u128 } }");
275    let (data_type, ident) = super::DataType::take(stream).unwrap();
276    assert_eq!(data_type, super::DataType::Enum);
277    assert_eq!(ident, "Foo");
278    let body = EnumBody::take(stream).unwrap();
279    assert_eq!(3, body.variants.len());
280
281    assert_eq!(body.variants[0].name, "Bar");
282    assert!(body.variants[0].fields.is_none());
283
284    assert_eq!(body.variants[1].name, "Baz");
285    assert!(body.variants[1].fields.is_some());
286    let fields = body.variants[1].fields.as_ref().unwrap();
287    assert_eq!(1, fields.len());
288    let (ident, field) = fields.get(0).unwrap();
289    assert!(ident.is_none());
290    assert_eq!(field.type_string(), "u8");
291
292    assert_eq!(body.variants[2].name, "Blah");
293    assert!(body.variants[2].fields.is_some());
294    let fields = body.variants[2].fields.as_ref().unwrap();
295    assert_eq!(2, fields.len());
296    let (ident, field) = fields.get(0).unwrap();
297    assert_eq!(ident.unwrap(), "a");
298    assert_eq!(field.type_string(), "u32");
299    let (ident, field) = fields.get(1).unwrap();
300    assert_eq!(ident.unwrap(), "b");
301    assert_eq!(field.type_string(), "u128");
302
303    let stream = &mut token_stream("enum Foo { Bar = -1, Baz = 2 }");
304    let (data_type, ident) = super::DataType::take(stream).unwrap();
305    assert_eq!(data_type, super::DataType::Enum);
306    assert_eq!(ident, "Foo");
307    let body = EnumBody::take(stream).unwrap();
308    assert_eq!(2, body.variants.len());
309
310    assert_eq!(body.variants[0].name, "Bar");
311    assert!(body.variants[0].fields.is_none());
312    assert_eq!(body.variants[0].get_integer(), -1);
313
314    assert_eq!(body.variants[1].name, "Baz");
315    assert!(body.variants[1].fields.is_none());
316    assert_eq!(body.variants[1].get_integer(), 2);
317
318    let stream = &mut token_stream("enum Foo { Bar(i32) = -1, Baz { a: i32 } = 2 }");
319    let (data_type, ident) = super::DataType::take(stream).unwrap();
320    assert_eq!(data_type, super::DataType::Enum);
321    assert_eq!(ident, "Foo");
322    let body = EnumBody::take(stream).unwrap();
323    assert_eq!(2, body.variants.len());
324
325    assert_eq!(body.variants[0].name, "Bar");
326    assert!(body.variants[0].fields.is_some());
327    let fields = body.variants[0].fields.as_ref().unwrap();
328    assert_eq!(fields.len(), 1);
329    assert!(matches!(fields.names()[0], IdentOrIndex::Index { index, .. } if index == 0));
330    assert_eq!(body.variants[0].get_integer(), -1);
331
332    assert_eq!(body.variants[1].name, "Baz");
333    assert!(body.variants[1].fields.is_some());
334    let fields = body.variants[1].fields.as_ref().unwrap();
335    assert_eq!(fields.len(), 1);
336    assert_eq!(fields.names().len(), 1);
337    assert!(matches!(&fields.names()[0], IdentOrIndex::Ident { ident, .. } if *ident == "a"));
338    assert_eq!(body.variants[1].get_integer(), 2);
339
340    let stream = &mut token_stream("enum Foo { Round(), Curly{}, Without }");
341    let (data_type, ident) = super::DataType::take(stream).unwrap();
342    assert_eq!(data_type, super::DataType::Enum);
343    assert_eq!(ident, "Foo");
344    let body = EnumBody::take(stream).unwrap();
345    assert_eq!(3, body.variants.len());
346
347    assert_eq!(body.variants[0].name, "Round");
348    assert!(body.variants[0].fields.is_some());
349    let fields = body.variants[0].fields.as_ref().unwrap();
350    assert!(fields.names().is_empty());
351    assert_eq!(fields.len(), 0);
352
353    assert_eq!(body.variants[1].name, "Curly");
354    assert!(body.variants[1].fields.is_some());
355    let fields = body.variants[1].fields.as_ref().unwrap();
356    assert!(fields.names().is_empty());
357    assert_eq!(fields.len(), 0);
358
359    assert_eq!(body.variants[2].name, "Without");
360    assert!(body.variants[2].fields.is_none());
361}
362
363/// A variant of an enum
364#[derive(Debug)]
365pub struct EnumVariant {
366    /// The name of the variant
367    pub name: Ident,
368    /// The field of the variant. See [`Fields`] for more info
369    pub fields: Option<Fields>,
370    /// The value of this variant. This can be one of:
371    /// - `Baz = 5`
372    /// - `Baz(i32) = 5`
373    /// - `Baz { a: i32} = 5`
374    ///
375    /// In either case this value will be `Some(Literal::i32(5))`
376    pub value: Option<Literal>,
377    /// The attributes of this variant
378    pub attributes: Vec<Attribute>,
379}
380
381#[cfg(test)]
382impl EnumVariant {
383    fn get_integer(&self) -> i64 {
384        let value = self.value.as_ref().expect("Variant has no value");
385        value
386            .to_string()
387            .parse()
388            .expect("Value is not a valid integer")
389    }
390}
391
392/// The different field types an enum variant can have.
393#[derive(Debug)]
394pub enum Fields {
395    /// Tuple-like variant
396    /// ```rs
397    /// enum Foo {
398    ///     Baz(u32)
399    /// }
400    /// struct Bar(u32);
401    /// ```
402    Tuple(Vec<UnnamedField>),
403
404    /// Struct-like variant
405    /// ```rs
406    /// enum Foo {
407    ///     Baz {
408    ///         baz: u32
409    ///     }
410    /// }
411    /// struct Bar {
412    ///     baz: u32
413    /// }
414    /// ```
415    Struct(Vec<(Ident, UnnamedField)>),
416}
417
418impl Fields {
419    /// Returns a list of names for the variant.
420    ///
421    /// ```
422    /// enum Foo {
423    ///     C(u32, u32), // will return `vec[Index { index: 0 }, Index { index: 1 }]`
424    ///     D { a: u32, b: u32 }, // will return `vec[Ident { ident: "a" }, Ident { ident: "b" }]`
425    /// }
426    pub fn names(&self) -> Vec<IdentOrIndex> {
427        let result: Vec<IdentOrIndex> = match self {
428            Self::Tuple(fields) => fields
429                .iter()
430                .enumerate()
431                .map(|(index, field)| IdentOrIndex::Index {
432                    index,
433                    span: field.span(),
434                    attributes: field.attributes.clone(),
435                })
436                .collect(),
437            Self::Struct(fields) => fields
438                .iter()
439                .map(|(ident, field)| IdentOrIndex::Ident {
440                    ident: ident.clone(),
441                    attributes: field.attributes.clone(),
442                })
443                .collect(),
444        };
445        result
446    }
447
448    /// Return the delimiter of the group for this variant
449    ///
450    /// ```
451    /// enum Foo {
452    ///     C(u32, u32), // will return `Delimiter::Paranthesis`
453    ///     D { a: u32, b: u32 }, // will return `Delimiter::Brace`
454    /// }
455    /// ```
456    pub fn delimiter(&self) -> Delimiter {
457        match self {
458            Self::Tuple(_) => Delimiter::Parenthesis,
459            Self::Struct(_) => Delimiter::Brace,
460        }
461    }
462}
463
464#[cfg(test)]
465impl Fields {
466    fn len(&self) -> usize {
467        match self {
468            Self::Tuple(fields) => fields.len(),
469            Self::Struct(fields) => fields.len(),
470        }
471    }
472
473    fn get(&self, index: usize) -> Option<(Option<&Ident>, &UnnamedField)> {
474        match self {
475            Self::Tuple(fields) => fields.get(index).map(|f| (None, f)),
476            Self::Struct(fields) => fields.get(index).map(|(ident, field)| (Some(ident), field)),
477        }
478    }
479}
480
481/// An unnamed field
482#[derive(Debug)]
483pub struct UnnamedField {
484    /// The visibility of the field
485    pub vis: Visibility,
486    /// The type of the field
487    pub r#type: Vec<TokenTree>,
488    /// The attributes of the field
489    pub attributes: Vec<Attribute>,
490}
491
492impl UnnamedField {
493    pub(crate) fn parse_with_name(
494        input: &mut Peekable<impl Iterator<Item = TokenTree>>,
495    ) -> Result<Vec<(Ident, Self)>> {
496        let mut result = Vec::new();
497        loop {
498            let attributes = Attribute::try_take(AttributeLocation::Field, input)?;
499            let vis = Visibility::try_take(input)?;
500
501            let ident = match input.peek() {
502                Some(TokenTree::Ident(_)) => assume_ident(input.next()),
503                Some(x) => {
504                    return Err(Error::InvalidRustSyntax {
505                        span: x.span(),
506                        expected: format!("ident or end of group, got {:?}", x),
507                    });
508                }
509                None => break,
510            };
511            match input.peek() {
512                Some(TokenTree::Punct(p)) if p.as_char() == ':' => {
513                    input.next();
514                }
515                token => return Error::wrong_token(token, ":"),
516            }
517            let r#type = read_tokens_until_punct(input, &[','])?;
518            consume_punct_if(input, ',');
519            result.push((
520                ident,
521                Self {
522                    vis,
523                    r#type,
524                    attributes,
525                },
526            ));
527        }
528        Ok(result)
529    }
530
531    pub(crate) fn parse(
532        input: &mut Peekable<impl Iterator<Item = TokenTree>>,
533    ) -> Result<Vec<Self>> {
534        let mut result = Vec::new();
535        while input.peek().is_some() {
536            let attributes = Attribute::try_take(AttributeLocation::Field, input)?;
537            let vis = Visibility::try_take(input)?;
538
539            let r#type = read_tokens_until_punct(input, &[','])?;
540            consume_punct_if(input, ',');
541            result.push(Self {
542                vis,
543                r#type,
544                attributes,
545            });
546        }
547        Ok(result)
548    }
549
550    /// Return [`type`] as a string. Useful for comparing it for known values.
551    ///
552    /// [`type`]: #structfield.type
553    pub fn type_string(&self) -> String {
554        self.r#type.iter().map(|t| t.to_string()).collect()
555    }
556
557    /// Return the span of [`type`].
558    ///
559    /// **note**: Until <https://github.com/rust-lang/rust/issues/54725> is stable, this will return the first span of the type instead
560    ///
561    /// [`type`]: #structfield.type
562    pub fn span(&self) -> Span {
563        // BlockedTODO: https://github.com/rust-lang/rust/issues/54725
564        // Span::join is unstable
565        // if let Some(first) = self.r#type.first() {
566        //     let mut span = first.span();
567        //     for token in self.r#type.iter().skip(1) {
568        //         span = span.join(span).unwrap();
569        //     }
570        //     span
571        // } else {
572        //     Span::call_site()
573        // }
574
575        match self.r#type.first() {
576            Some(first) => first.span(),
577            None => Span::call_site(),
578        }
579    }
580}
581
582/// Reference to an enum variant's field. Either by index or by ident.
583///
584/// ```
585/// enum Foo {
586///     Bar(u32), // will be IdentOrIndex::Index { index: 0, .. }
587///     Baz {
588///         a: u32, // will be IdentOrIndex::Ident { ident: "a", .. }
589///     },
590/// }
591#[derive(Debug, Clone)]
592pub enum IdentOrIndex {
593    /// The variant is a named field
594    Ident {
595        /// The name of the field
596        ident: Ident,
597        /// The attributes of the field
598        attributes: Vec<Attribute>,
599    },
600    /// The variant is an unnamed field
601    Index {
602        /// The field index
603        index: usize,
604        /// The span of the field type
605        span: Span,
606        /// The attributes of this field
607        attributes: Vec<Attribute>,
608    },
609}
610
611impl IdentOrIndex {
612    /// Get the ident. Will panic if this is an `IdentOrIndex::Index`
613    pub fn unwrap_ident(&self) -> Ident {
614        match self {
615            Self::Ident { ident, .. } => ident.clone(),
616            x => panic!("Expected ident, found {:?}", x),
617        }
618    }
619
620    /// Convert this ident into a TokenTree. If this is an `Index`, will return `prefix + index` instead.
621    pub fn to_token_tree_with_prefix(&self, prefix: &str) -> TokenTree {
622        TokenTree::Ident(match self {
623            IdentOrIndex::Ident { ident, .. } => (*ident).clone(),
624            IdentOrIndex::Index { index, span, .. } => {
625                let name = format!("{}{}", prefix, index);
626                Ident::new(&name, *span)
627            }
628        })
629    }
630
631    /// Return either the index or the ident of this field with a fixed prefix. The prefix will always be added.
632    pub fn to_string_with_prefix(&self, prefix: &str) -> String {
633        match self {
634            IdentOrIndex::Ident { ident, .. } => ident.to_string(),
635            IdentOrIndex::Index { index, .. } => {
636                format!("{}{}", prefix, index)
637            }
638        }
639    }
640
641    /// Returns the attributes of this field.
642    pub fn attributes(&self) -> &Vec<Attribute> {
643        match self {
644            Self::Ident { attributes, .. } => attributes,
645            Self::Index { attributes, .. } => attributes,
646        }
647    }
648}
649
650impl std::fmt::Display for IdentOrIndex {
651    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
652        match self {
653            IdentOrIndex::Ident { ident, .. } => write!(fmt, "{}", ident),
654            IdentOrIndex::Index { index, .. } => write!(fmt, "{}", index),
655        }
656    }
657}
658
659#[test]
660fn enum_explicit_variants() {
661    use crate::token_stream;
662    let stream = &mut token_stream("{ A = 1, B = 2 }");
663    let body = EnumBody::take(stream).unwrap();
664    assert_eq!(body.variants.len(), 2);
665}