Skip to main content

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}