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: impl Into<String>) -> Self {
59 Function {
60 name: name.into(),
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: impl Into<String>) -> &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: impl Into<String>) -> &mut Self {
102 self.generics.push(name.into());
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: String::new(),
136 annotation: Vec::new(),
137 value: String::new(),
138 visibility: None,
139 });
140
141 self
142 }
143
144 pub fn ret<T>(&mut self, ty: T) -> &mut Self
146 where
147 T: Into<Type>,
148 {
149 self.ret = Some(ty.into());
150 self
151 }
152
153 pub fn bound<T>(&mut self, name: &str, ty: T) -> &mut Self
155 where
156 T: Into<Type>,
157 {
158 self.bounds.push(Bound {
159 name: name.to_string(),
160 bound: vec![ty.into()],
161 });
162 self
163 }
164
165 pub fn line<T>(&mut self, line: T) -> &mut Self
167 where
168 T: ToString,
169 {
170 self.body
171 .get_or_insert(vec![])
172 .push(Body::String(line.to_string()));
173
174 self
175 }
176
177 pub fn attr(&mut self, attribute: &str) -> &mut Self {
188 self.attributes.push(attribute.to_string());
189 self
190 }
191
192 pub fn extern_abi(&mut self, abi: &str) -> &mut Self {
202 self.extern_abi.replace(abi.to_string());
203 self
204 }
205
206 pub fn push_block(&mut self, block: Block) -> &mut Self {
208 self.body.get_or_insert(vec![]).push(Body::Block(block));
209
210 self
211 }
212
213 pub fn fmt(&self, is_trait: bool, fmt: &mut Formatter<'_>) -> fmt::Result {
215 if let Some(ref docs) = self.docs {
216 docs.fmt(fmt)?;
217 }
218
219 if let Some(ref allow) = self.allow {
220 write!(fmt, "#[allow({})]\n", allow)?;
221 }
222
223 for attr in self.attributes.iter() {
224 write!(fmt, "#[{}]\n", attr)?;
225 }
226
227 if is_trait {
228 assert!(
229 self.vis.is_none(),
230 "trait fns do not have visibility modifiers"
231 );
232 }
233
234 if let Some(ref vis) = self.vis {
235 write!(fmt, "{} ", vis)?;
236 }
237
238 if let Some(ref extern_abi) = self.extern_abi {
239 write!(fmt, "extern \"{extern_abi}\" ", extern_abi = extern_abi)?;
240 }
241
242 if self.r#async {
243 write!(fmt, "async ")?;
244 }
245
246 write!(fmt, "fn {}", self.name)?;
247 fmt_generics(&self.generics, fmt)?;
248
249 write!(fmt, "(")?;
250
251 if let Some(ref s) = self.arg_self {
252 write!(fmt, "{}", s)?;
253 }
254
255 for (i, arg) in self.args.iter().enumerate() {
256 if i != 0 || self.arg_self.is_some() {
257 write!(fmt, ", ")?;
258 }
259
260 write!(fmt, "{}: ", arg.name)?;
261 arg.ty.fmt(fmt)?;
262 }
263
264 write!(fmt, ")")?;
265
266 if let Some(ref ret) = self.ret {
267 write!(fmt, " -> ")?;
268 ret.fmt(fmt)?;
269 }
270
271 fmt_bounds(&self.bounds, fmt)?;
272
273 match self.body {
274 Some(ref body) => fmt.block(|fmt| {
275 for b in body {
276 b.fmt(fmt)?;
277 }
278
279 Ok(())
280 }),
281 None => {
282 if !is_trait {
283 panic!("impl blocks must define fn bodies");
284 }
285
286 write!(fmt, ";\n")
287 }
288 }
289 }
290}