1use std::fmt::{self, Write};
2
3use crate::block::Block;
4use crate::body::Body;
5use crate::bound::Bound;
6use crate::docs::Docs;
7use crate::field::Field;
8use crate::formatter::Formatter;
9use crate::formatter::{fmt_bounds, fmt_generics};
10
11use crate::r#type::Type;
12
13#[derive(Debug, Clone)]
15pub struct Function {
16 name: String,
18
19 docs: Option<Docs>,
21
22 allow: Option<String>,
24
25 vis: Option<String>,
27
28 generics: Vec<String>,
30
31 arg_self: Option<String>,
33
34 args: Vec<Field>,
36
37 ret: Option<Type>,
39
40 bounds: Vec<Bound>,
42
43 pub body: Option<Vec<Body>>,
45
46 attributes: Vec<String>,
48
49 extern_abi: Option<String>,
51
52 r#async: bool,
54}
55
56impl Function {
57 pub fn new(name: &str) -> Self {
59 Self {
60 name: name.to_string(),
61 docs: None,
62 allow: None,
63 vis: None,
64 generics: vec![],
65 arg_self: None,
66 args: vec![],
67 ret: None,
68 bounds: vec![],
69 body: Some(vec![]),
70 attributes: vec![],
71 extern_abi: None,
72 r#async: false,
73 }
74 }
75
76 pub fn doc(&mut self, docs: &str) -> &mut Self {
78 self.docs = Some(Docs::new(docs));
79 self
80 }
81
82 pub fn allow(&mut self, allow: &str) -> &mut Self {
84 self.allow = Some(allow.to_string());
85 self
86 }
87
88 pub fn vis(&mut self, vis: &str) -> &mut Self {
90 self.vis = Some(vis.to_string());
91 self
92 }
93
94 pub fn set_async(&mut self, r#async: bool) -> &mut Self {
96 self.r#async = r#async;
97 self
98 }
99
100 pub fn generic(&mut self, name: &str) -> &mut Self {
102 self.generics.push(name.to_string());
103 self
104 }
105
106 pub fn arg_self(&mut self) -> &mut Self {
108 self.arg_self = Some("self".to_string());
109 self
110 }
111
112 pub fn arg_ref_self(&mut self) -> &mut Self {
114 self.arg_self = Some("&self".to_string());
115 self
116 }
117
118 pub fn arg_mut_self(&mut self) -> &mut Self {
120 self.arg_self = Some("&mut self".to_string());
121 self
122 }
123
124 pub fn arg<T>(&mut self, name: &str, ty: T) -> &mut Self
126 where
127 T: Into<Type>,
128 {
129 self.args.push(Field {
130 name: name.to_string(),
131 ty: ty.into(),
132 documentation: Vec::new(),
136 annotation: Vec::new(),
137 });
138
139 self
140 }
141
142 pub fn ret<T>(&mut self, ty: T) -> &mut Self
144 where
145 T: Into<Type>,
146 {
147 self.ret = Some(ty.into());
148 self
149 }
150
151 pub fn bound<T>(&mut self, name: &str, ty: T) -> &mut Self
153 where
154 T: Into<Type>,
155 {
156 self.bounds.push(Bound {
157 name: name.to_string(),
158 bound: vec![ty.into()],
159 });
160 self
161 }
162
163 pub fn line<T>(&mut self, line: T) -> &mut Self
165 where
166 T: ToString,
167 {
168 self.body
169 .get_or_insert(vec![])
170 .push(Body::String(line.to_string()));
171
172 self
173 }
174
175 pub fn attr(&mut self, attribute: &str) -> &mut Self {
186 self.attributes.push(attribute.to_string());
187 self
188 }
189
190 pub fn extern_abi(&mut self, abi: &str) -> &mut Self {
200 self.extern_abi.replace(abi.to_string());
201 self
202 }
203
204 pub fn push_block(&mut self, block: Block) -> &mut Self {
206 self.body.get_or_insert(vec![]).push(Body::Block(block));
207
208 self
209 }
210
211 pub fn fmt(&self, is_trait: bool, fmt: &mut Formatter<'_>) -> fmt::Result {
213 if let Some(docs) = &self.docs {
214 docs.fmt(fmt)?;
215 }
216
217 if let Some(allow) = &self.allow {
218 writeln!(fmt, "#[allow({})]", allow)?;
219 }
220
221 for attr in self.attributes.iter() {
222 writeln!(fmt, "#[{}]", attr)?;
223 }
224
225 if is_trait {
226 assert!(
227 self.vis.is_none(),
228 "trait fns do not have visibility modifiers"
229 );
230 }
231
232 if let Some(vis) = &self.vis {
233 write!(fmt, "{} ", vis)?;
234 }
235
236 if let Some(extern_abi) = &self.extern_abi {
237 write!(fmt, "extern \"{extern_abi}\" ", extern_abi = extern_abi)?;
238 }
239
240 if self.r#async {
241 write!(fmt, "async ")?;
242 }
243
244 write!(fmt, "fn {}", self.name)?;
245 fmt_generics(&self.generics, fmt)?;
246
247 write!(fmt, "(")?;
248
249 if let Some(s) = &self.arg_self {
250 write!(fmt, "{}", s)?;
251 }
252
253 for (i, arg) in self.args.iter().enumerate() {
254 if i != 0 || self.arg_self.is_some() {
255 write!(fmt, ", ")?;
256 }
257
258 write!(fmt, "{}: ", arg.name)?;
259 arg.ty.fmt(fmt)?;
260 }
261
262 write!(fmt, ")")?;
263
264 if let Some(ret) = &self.ret {
265 write!(fmt, " -> ")?;
266 ret.fmt(fmt)?;
267 }
268
269 fmt_bounds(&self.bounds, fmt)?;
270
271 match &self.body {
272 Some(body) => fmt.block(|fmt| {
273 for b in body {
274 b.fmt(fmt)?;
275 }
276
277 Ok(())
278 }),
279 None => {
280 if !is_trait {
281 panic!("impl blocks must define fn bodies");
282 }
283
284 writeln!(fmt, ";")
285 }
286 }
287 }
288}