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