Skip to main content

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}