rune/ast/
fields.rs

1use core::iter;
2use core::slice;
3
4use crate::ast::prelude::*;
5
6/// An item body declaration.
7#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, OptionSpanned)]
8#[non_exhaustive]
9pub enum Fields {
10    /// A regular body.
11    Named(ast::Braced<ast::Field, T![,]>),
12    /// A tuple body.
13    Unnamed(ast::Parenthesized<ast::Field, T![,]>),
14    /// An empty body.
15    Empty,
16}
17
18impl Fields {
19    /// If the body needs to be terminated with a semicolon.
20    pub(crate) fn needs_semi_colon(&self) -> bool {
21        matches!(self, Self::Empty | Self::Unnamed(..))
22    }
23
24    /// Iterate over the fields of the body.
25    pub(crate) fn fields(&self) -> impl Iterator<Item = &'_ (ast::Field, Option<T![,]>)> {
26        match self {
27            Fields::Empty => IntoIterator::into_iter(&[]),
28            Fields::Unnamed(body) => body.iter(),
29            Fields::Named(body) => body.iter(),
30        }
31    }
32}
33
34impl Parse for Fields {
35    fn parse(p: &mut Parser<'_>) -> Result<Self> {
36        Ok(match p.nth(0)? {
37            K!['('] => Self::Unnamed(p.parse()?),
38            K!['{'] => Self::Named(p.parse()?),
39            _ => Self::Empty,
40        })
41    }
42}
43
44type ToField = fn(&(ast::Field, Option<T![,]>)) -> &ast::Field;
45
46fn to_field((field, _): &(ast::Field, Option<T![,]>)) -> &ast::Field {
47    field
48}
49
50impl<'a> IntoIterator for &'a Fields {
51    type Item = &'a ast::Field;
52    type IntoIter = iter::Map<slice::Iter<'a, (ast::Field, Option<T![,]>)>, ToField>;
53
54    fn into_iter(self) -> Self::IntoIter {
55        static STATIC: &[(ast::Field, Option<T![,]>); 0] = &[];
56
57        match self {
58            Fields::Named(fields) => fields.iter().map(to_field as ToField),
59            Fields::Unnamed(fields) => fields.iter().map(to_field as ToField),
60            Fields::Empty => STATIC.iter().map(to_field as ToField),
61        }
62    }
63}