codegen/
fields.rs

1use std::fmt::{self, Write};
2
3use crate::field::Field;
4use crate::formatter::Formatter;
5
6use crate::r#type::Type;
7
8/// Defines a set of fields.
9#[derive(Debug, Clone)]
10pub enum Fields {
11    Empty,
12    Tuple(Vec<Type>),
13    Named(Vec<Field>),
14}
15
16impl Fields {
17    pub fn push_named(&mut self, field: Field) -> &mut Self {
18        match *self {
19            Fields::Empty => {
20                *self = Fields::Named(vec![field]);
21            }
22            Fields::Named(ref mut fields) => {
23                fields.push(field);
24            }
25            _ => panic!("field list is named"),
26        }
27
28        self
29    }
30
31    pub fn named<T>(&mut self, name: &str, ty: T) -> &mut Self
32    where
33        T: Into<Type>,
34    {
35        self.push_named(Field {
36            name: name.to_string(),
37            ty: ty.into(),
38            documentation: String::new(),
39            annotation: Vec::new(),
40            value: String::new(),
41            visibility: None,
42        })
43    }
44
45    pub fn new_named<T>(&mut self, name: impl Into<String>, ty: T) -> &mut Field
46    where
47        T: Into<Type>,
48    {
49        self.named(&name.into(), ty);
50        if let Fields::Named(ref mut fields) = *self {
51            fields.last_mut().unwrap()
52        } else {
53            unreachable!()
54        }
55    }
56
57    pub fn tuple<T>(&mut self, ty: T) -> &mut Self
58    where
59        T: Into<Type>,
60    {
61        match *self {
62            Fields::Empty => {
63                *self = Fields::Tuple(vec![ty.into()]);
64            }
65            Fields::Tuple(ref mut fields) => {
66                fields.push(ty.into());
67            }
68            _ => panic!("field list is tuple"),
69        }
70
71        self
72    }
73
74    pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
75        match *self {
76            Fields::Named(ref fields) => {
77                assert!(!fields.is_empty());
78
79                fmt.block(|fmt| {
80                    for f in fields {
81                        if !f.documentation.is_empty() {
82                            for doc in f.documentation.lines() {
83                                write!(fmt, "/// {}\n", doc)?;
84                            }
85                        }
86                        if !f.annotation.is_empty() {
87                            for ann in &f.annotation {
88                                write!(fmt, "{}\n", ann)?;
89                            }
90                        }
91                        if let Some(ref visibility) = f.visibility {
92                            write!(fmt, "{} ", visibility)?;
93                        }
94                        write!(fmt, "{}: ", f.name)?;
95                        f.ty.fmt(fmt)?;
96                        write!(fmt, ",\n")?;
97                    }
98
99                    Ok(())
100                })?;
101            }
102            Fields::Tuple(ref tys) => {
103                assert!(!tys.is_empty());
104
105                write!(fmt, "(")?;
106
107                for (i, ty) in tys.iter().enumerate() {
108                    if i != 0 {
109                        write!(fmt, ", ")?;
110                    }
111                    ty.fmt(fmt)?;
112                }
113
114                write!(fmt, ")")?;
115            }
116            Fields::Empty => {}
117        }
118
119        Ok(())
120    }
121}