virtue_next/generate/generate_item.rs
1use super::StreamBuilder;
2use crate::{
3 parse::Visibility,
4 prelude::{Delimiter, Result},
5};
6
7/// A builder for constants.
8pub struct GenConst<'a> {
9 consts: &'a mut Vec<StreamBuilder>,
10 attrs: Vec<String>,
11 name: String,
12 ty: String,
13 vis: Visibility,
14}
15
16impl<'a> GenConst<'a> {
17 pub(crate) fn new(
18 consts: &'a mut Vec<StreamBuilder>,
19 name: impl Into<String>,
20 ty: impl Into<String>,
21 ) -> Self {
22 Self {
23 consts,
24 attrs: Vec::new(),
25 name: name.into(),
26 ty: ty.into(),
27 vis: Visibility::Default,
28 }
29 }
30
31 /// Make the const `pub`. By default the const will have no visibility modifier and will only be visible in the current scope.
32 #[must_use]
33 pub fn make_pub(mut self) -> Self {
34 self.vis = Visibility::Pub;
35 self
36 }
37
38 /// Add an outer attribute
39 #[must_use]
40 pub fn with_attr(mut self, attr: impl Into<String>) -> Self {
41 self.attrs.push(attr.into());
42 self
43 }
44
45 /// Complete the constant definition. This function takes a callback that will form the value of the constant.
46 ///
47 /// ```
48 /// # use virtue::prelude::Generator;
49 /// # let mut generator = Generator::with_name("Bar");
50 /// generator.impl_for("Foo")
51 /// .generate_const("BAR", "u8")
52 /// .with_value(|b| {
53 /// b.push_parsed("5")?;
54 /// Ok(())
55 /// })?;
56 /// # generator.assert_eq("impl Foo for Bar { const BAR : u8 = 5 ; }");
57 /// # Ok::<_, virtue::Error>(())
58 /// ```
59 ///
60 /// Generates:
61 /// ```ignore
62 /// impl Foo for <struct or enum> {
63 /// const BAR: u8 = 5;
64 /// }
65 /// ```
66 pub fn with_value<F>(self, f: F) -> Result
67 where
68 F: FnOnce(&mut StreamBuilder) -> Result,
69 {
70 let mut builder = StreamBuilder::new();
71
72 for attr in self.attrs {
73 builder
74 .punct('#')
75 .punct('!')
76 .group(Delimiter::Bracket, |builder| {
77 builder.push_parsed(attr)?;
78 Ok(())
79 })?;
80 }
81
82 if self.vis == Visibility::Pub {
83 builder.ident_str("pub");
84 }
85
86 builder
87 .ident_str("const")
88 .push_parsed(self.name)?
89 .punct(':')
90 .push_parsed(self.ty)?
91 .punct('=');
92 f(&mut builder)?;
93 builder.punct(';');
94
95 self.consts.push(builder);
96 Ok(())
97 }
98}
99
100/// A builder for functions.
101pub struct FnBuilder<'a, P> {
102 parent: &'a mut P,
103 name: String,
104
105 attrs: Vec<String>,
106 is_async: bool,
107 lifetimes: Vec<(String, Vec<String>)>,
108 generics: Vec<(String, Vec<String>)>,
109 self_arg: FnSelfArg,
110 args: Vec<(String, String)>,
111 return_type: Option<String>,
112 vis: Visibility,
113}
114
115impl<'a, P: FnParent> FnBuilder<'a, P> {
116 pub(super) fn new(parent: &'a mut P, name: impl Into<String>) -> Self {
117 Self {
118 parent,
119 name: name.into(),
120 attrs: Vec::new(),
121 is_async: false,
122 lifetimes: Vec::new(),
123 generics: Vec::new(),
124 self_arg: FnSelfArg::None,
125 args: Vec::new(),
126 return_type: None,
127 vis: Visibility::Default,
128 }
129 }
130
131 /// Add an outer attribute
132 #[must_use]
133 pub fn with_attr(mut self, attr: impl Into<String>) -> Self {
134 self.attrs.push(attr.into());
135 self
136 }
137
138 /// Add a lifetime parameter.
139 ///
140 /// ```
141 /// # use virtue::prelude::Generator;
142 /// # let mut generator = Generator::with_name("Foo");
143 /// generator
144 /// .r#impl()
145 /// .generate_fn("foo") // fn foo()
146 /// .with_lifetime("a") // fn foo<'a>()
147 /// # .body(|_| Ok(())).unwrap();
148 /// # generator.assert_eq("impl Foo { fn foo < 'a > () { } }");
149 /// ```
150 #[must_use]
151 pub fn with_lifetime(mut self, name: impl Into<String>) -> Self {
152 self.lifetimes.push((name.into(), Vec::new()));
153 self
154 }
155
156 /// Make the function async
157 ///
158 /// ```
159 /// # use virtue::prelude::Generator;
160 /// # let mut generator = Generator::with_name("Foo");
161 /// generator
162 /// .r#impl()
163 /// .generate_fn("foo") // fn foo()
164 /// .as_async() // async fn foo()
165 /// # .body(|_| Ok(())).unwrap();
166 /// # generator.assert_eq("impl Foo { async fn foo () { } }");
167 /// ```
168 #[must_use]
169 pub fn as_async(mut self) -> Self {
170 self.is_async = true;
171 self
172 }
173
174 /// Add a lifetime parameter.
175 ///
176 /// `dependencies` are the lifetime dependencies of the given lifetime.
177 ///
178 /// ```
179 /// # use virtue::prelude::Generator;
180 /// # let mut generator = Generator::with_name("Foo");
181 /// generator
182 /// .r#impl()
183 /// .generate_fn("foo") // fn foo()
184 /// .with_lifetime("a") // fn foo<'a>()
185 /// .with_lifetime_deps("b", ["a"]) // fn foo<'b: 'a>()
186 /// # .body(|_| Ok(())).unwrap();
187 /// # generator.assert_eq("impl Foo { fn foo < 'a , 'b : 'a > () { } }");
188 /// ```
189 #[must_use]
190 pub fn with_lifetime_deps<ITER, I>(
191 mut self,
192 name: impl Into<String>,
193 dependencies: ITER,
194 ) -> Self
195 where
196 ITER: IntoIterator<Item = I>,
197 I: Into<String>,
198 {
199 self.lifetimes.push((
200 name.into(),
201 dependencies.into_iter().map(Into::into).collect(),
202 ));
203 self
204 }
205
206 /// Add a generic parameter. Keep in mind that will *not* work for lifetimes.
207 ///
208 /// ```
209 /// # use virtue::prelude::Generator;
210 /// # let mut generator = Generator::with_name("Foo");
211 /// generator
212 /// .r#impl()
213 /// .generate_fn("foo") // fn foo()
214 /// .with_generic("D") // fn foo<D>()
215 /// # .body(|_| Ok(())).unwrap();
216 /// # generator.assert_eq("impl Foo { fn foo < D > () { } }");
217 /// ```
218 #[must_use]
219 pub fn with_generic(mut self, name: impl Into<String>) -> Self {
220 self.generics.push((name.into(), Vec::new()));
221 self
222 }
223
224 /// Add a generic parameter. Keep in mind that will *not* work for lifetimes.
225 ///
226 /// `dependencies` are the dependencies of the parameter.
227 ///
228 /// ```
229 /// # use virtue::prelude::Generator;
230 /// # let mut generator = Generator::with_name("Foo");
231 /// generator
232 /// .r#impl()
233 /// .generate_fn("foo") // fn foo()
234 /// .with_generic("D") // fn foo<D>()
235 /// .with_generic_deps("E", ["Encodable"]) // fn foo<D, E: Encodable>();
236 /// # .body(|_| Ok(())).unwrap();
237 /// # generator.assert_eq("impl Foo { fn foo < D , E : Encodable > () { } }");
238 /// ```
239 #[must_use]
240 pub fn with_generic_deps<DEP, I>(mut self, name: impl Into<String>, dependencies: DEP) -> Self
241 where
242 DEP: IntoIterator<Item = I>,
243 I: Into<String>,
244 {
245 self.generics.push((
246 name.into(),
247 dependencies.into_iter().map(Into::into).collect(),
248 ));
249 self
250 }
251
252 /// Set the value for `self`. See [FnSelfArg] for more information.
253 ///
254 /// ```
255 /// # use virtue::prelude::{Generator, FnSelfArg};
256 /// # let mut generator = Generator::with_name("Foo");
257 /// generator
258 /// .r#impl()
259 /// .generate_fn("foo") // fn foo()
260 /// .with_self_arg(FnSelfArg::RefSelf) // fn foo(&self)
261 /// # .body(|_| Ok(())).unwrap();
262 /// # generator.assert_eq("impl Foo { fn foo (& self ,) { } }");
263 /// ```
264 #[must_use]
265 pub fn with_self_arg(mut self, self_arg: FnSelfArg) -> Self {
266 self.self_arg = self_arg;
267 self
268 }
269
270 /// Add an argument with a `name` and a `ty`.
271 ///
272 /// ```
273 /// # use virtue::prelude::Generator;
274 /// # let mut generator = Generator::with_name("Foo");
275 /// generator
276 /// .r#impl()
277 /// .generate_fn("foo") // fn foo()
278 /// .with_arg("a", "u32") // fn foo(a: u32)
279 /// .with_arg("b", "u32") // fn foo(a: u32, b: u32)
280 /// # .body(|_| Ok(())).unwrap();
281 /// # generator.assert_eq("impl Foo { fn foo (a : u32 , b : u32) { } }");
282 /// ```
283 #[must_use]
284 pub fn with_arg(mut self, name: impl Into<String>, ty: impl Into<String>) -> Self {
285 self.args.push((name.into(), ty.into()));
286 self
287 }
288
289 /// Set the return type for the function. By default the function will have no return type.
290 ///
291 /// ```
292 /// # use virtue::prelude::Generator;
293 /// # let mut generator = Generator::with_name("Foo");
294 /// generator
295 /// .r#impl()
296 /// .generate_fn("foo") // fn foo()
297 /// .with_return_type("u32") // fn foo() -> u32
298 /// # .body(|_| Ok(())).unwrap();
299 /// # generator.assert_eq("impl Foo { fn foo () ->u32 { } }");
300 /// ```
301 #[must_use]
302 pub fn with_return_type(mut self, ret_type: impl Into<String>) -> Self {
303 self.return_type = Some(ret_type.into());
304 self
305 }
306
307 /// Make the function `pub`. If this is not called, the function will have no visibility modifier.
308 #[must_use]
309 pub fn make_pub(mut self) -> Self {
310 self.vis = Visibility::Pub;
311 self
312 }
313
314 /// Complete the function definition. This function takes a callback that will form the body of the function.
315 ///
316 /// ```
317 /// # use virtue::prelude::Generator;
318 /// # let mut generator = Generator::with_name("Foo");
319 /// generator
320 /// .r#impl()
321 /// .generate_fn("foo") // fn foo()
322 /// .body(|b| {
323 /// b.push_parsed("println!(\"hello world\");")?;
324 /// Ok(())
325 /// })
326 /// .unwrap();
327 /// // fn foo() {
328 /// // println!("Hello world");
329 /// // }
330 /// # generator.assert_eq("impl Foo { fn foo () { println ! (\"hello world\") ; } }");
331 /// ```
332 pub fn body(
333 self,
334 body_builder: impl FnOnce(&mut StreamBuilder) -> crate::Result,
335 ) -> crate::Result {
336 let FnBuilder {
337 parent,
338 name,
339 attrs,
340 is_async,
341 lifetimes,
342 generics,
343 self_arg,
344 args,
345 return_type,
346 vis,
347 } = self;
348
349 let mut builder = StreamBuilder::new();
350
351 // attrs
352 for attr in attrs {
353 builder.punct('#').group(Delimiter::Bracket, |builder| {
354 builder.push_parsed(attr)?;
355 Ok(())
356 })?;
357 }
358
359 // function name; `fn name`
360 if vis == Visibility::Pub {
361 builder.ident_str("pub");
362 }
363 if is_async {
364 builder.ident_str("async");
365 }
366 builder.ident_str("fn");
367 builder.ident_str(name);
368
369 // lifetimes; `<'a: 'b, D: Display>`
370 if !lifetimes.is_empty() || !generics.is_empty() {
371 builder.punct('<');
372 let mut is_first = true;
373 for (lifetime, dependencies) in lifetimes {
374 if is_first {
375 is_first = false;
376 } else {
377 builder.punct(',');
378 }
379 builder.lifetime_str(lifetime.as_ref());
380 if !dependencies.is_empty() {
381 for (idx, dependency) in dependencies.into_iter().enumerate() {
382 builder.punct(if idx == 0 { ':' } else { '+' });
383 builder.lifetime_str(dependency.as_ref());
384 }
385 }
386 }
387 for (generic, dependencies) in generics {
388 if is_first {
389 is_first = false;
390 } else {
391 builder.punct(',');
392 }
393 builder.ident_str(&generic);
394 if !dependencies.is_empty() {
395 for (idx, dependency) in dependencies.into_iter().enumerate() {
396 builder.punct(if idx == 0 { ':' } else { '+' });
397 builder.push_parsed(&dependency)?;
398 }
399 }
400 }
401 builder.punct('>');
402 }
403
404 // Arguments; `(&self, foo: &Bar)`
405 builder.group(Delimiter::Parenthesis, |arg_stream| {
406 if let Some(self_arg) = self_arg.into_token_tree() {
407 arg_stream.append(self_arg);
408 arg_stream.punct(',');
409 }
410 for (idx, (arg_name, arg_ty)) in args.into_iter().enumerate() {
411 if idx != 0 {
412 arg_stream.punct(',');
413 }
414 arg_stream.push_parsed(&arg_name)?;
415 arg_stream.punct(':');
416 arg_stream.push_parsed(&arg_ty)?;
417 }
418 Ok(())
419 })?;
420
421 // Return type: `-> ResultType`
422 if let Some(return_type) = return_type {
423 builder.puncts("->");
424 builder.push_parsed(&return_type)?;
425 }
426
427 let mut body_stream = StreamBuilder::new();
428 body_builder(&mut body_stream)?;
429
430 parent.append(builder, body_stream)
431 }
432}
433
434pub trait FnParent {
435 fn append(&mut self, fn_definition: StreamBuilder, fn_body: StreamBuilder) -> Result;
436}
437
438/// The `self` argument of a function
439#[allow(dead_code)]
440#[non_exhaustive]
441pub enum FnSelfArg {
442 /// No `self` argument. The function will be a static function.
443 None,
444
445 /// `self`. The function will consume self.
446 TakeSelf,
447
448 /// `mut self`. The function will consume self.
449 MutTakeSelf,
450
451 /// `&self`. The function will take self by reference.
452 RefSelf,
453
454 /// `&mut self`. The function will take self by mutable reference.
455 MutSelf,
456}
457
458impl FnSelfArg {
459 fn into_token_tree(self) -> Option<StreamBuilder> {
460 let mut builder = StreamBuilder::new();
461 match self {
462 Self::None => return None,
463 Self::TakeSelf => {
464 builder.ident_str("self");
465 }
466 Self::MutTakeSelf => {
467 builder.ident_str("mut");
468 builder.ident_str("self");
469 }
470 Self::RefSelf => {
471 builder.punct('&');
472 builder.ident_str("self");
473 }
474 Self::MutSelf => {
475 builder.punct('&');
476 builder.ident_str("mut");
477 builder.ident_str("self");
478 }
479 }
480 Some(builder)
481 }
482}