Skip to main content

virtue_next/generate/
generate_mod.rs

1use super::GenEnum;
2use super::GenStruct;
3use super::Impl;
4use super::Parent;
5use super::StreamBuilder;
6use crate::Result;
7use crate::parse::Visibility;
8use crate::prelude::Delimiter;
9use crate::prelude::Ident;
10use crate::prelude::Span;
11
12/// Builder for generating a module with its contents.
13pub struct GenerateMod<'a, P: Parent> {
14    parent: &'a mut P,
15    name: Ident,
16    uses: Vec<StreamBuilder>,
17    vis: Visibility,
18    content: StreamBuilder,
19}
20
21impl<'a, P: Parent> GenerateMod<'a, P> {
22    pub(crate) fn new(
23        parent: &'a mut P,
24        name: impl Into<String>,
25    ) -> Self {
26        Self {
27            parent,
28            name: Ident::new(name.into().as_str(), Span::call_site()),
29            uses: Vec::new(),
30            vis: Visibility::Default,
31            content: StreamBuilder::new(),
32        }
33    }
34
35    /// Add a `use ...;` to the current mod
36    ///
37    /// `generator.impl_mod("foo").add_use("bar")` will generate:
38    ///
39    /// ```ignore
40    /// mod foo {
41    ///     use bar;
42    /// }
43    /// ```
44    ///
45    /// This is especially useful with `.add_use("super::*");`, which will pull all parent imports into scope
46    ///
47    /// # Errors
48    ///
49    /// Returns an error if parsing fails.
50    pub fn add_use(
51        &mut self,
52        r#use: impl AsRef<str>,
53    ) -> Result {
54        let mut builder = StreamBuilder::new();
55        builder.ident_str("use").push_parsed(r#use)?.punct(';');
56        self.uses.push(builder);
57        Ok(())
58    }
59
60    /// Generate a struct with the given name. See [`GenStruct`] for more info.
61    pub fn generate_struct(
62        &mut self,
63        name: impl Into<String>,
64    ) -> GenStruct<'_, Self> {
65        GenStruct::new(self, name)
66    }
67
68    /// Generate an enum with the given name. See [`GenEnum`] for more info.
69    pub fn generate_enum(
70        &mut self,
71        name: impl Into<String>,
72    ) -> GenEnum<'_, Self> {
73        GenEnum::new(self, name)
74    }
75
76    /// Generate an `impl <name>` implementation. See [`Impl`] for more information.
77    pub fn r#impl(
78        &mut self,
79        name: impl Into<String>,
80    ) -> Impl<'_, Self> {
81        Impl::new(self, name)
82    }
83
84    /// Generate an `impl <name>` implementation. See [`Impl`] for more information.
85    ///
86    /// Alias for [`impl`] which doesn't need a `r#` prefix.
87    ///
88    /// [`impl`]: #method.impl
89    ///
90    /// # Panics
91    ///
92    /// Panics if an internal invariant is violated.
93    pub fn generate_impl(
94        &mut self,
95        name: impl Into<String>,
96    ) -> Impl<'_, Self> {
97        Impl::new(self, name)
98    }
99}
100
101impl<P: Parent> Drop for GenerateMod<'_, P> {
102    fn drop(&mut self) {
103        let mut builder = StreamBuilder::new();
104        if self.vis == Visibility::Pub {
105            builder.ident_str("pub");
106        }
107        builder
108            .ident_str("mod")
109            .ident(self.name.clone())
110            .group(Delimiter::Brace, |group| {
111                for r#use in std::mem::take(&mut self.uses) {
112                    group.append(r#use);
113                }
114                group.append(std::mem::take(&mut self.content));
115                Ok(())
116            })
117            .unwrap();
118
119        self.parent.append(builder);
120    }
121}
122
123impl<P: Parent> Parent for GenerateMod<'_, P> {
124    fn append(
125        &mut self,
126        builder: StreamBuilder,
127    ) {
128        self.content.append(builder);
129    }
130
131    fn name(&self) -> &crate::prelude::Ident {
132        &self.name
133    }
134
135    fn generics(&self) -> Option<&crate::parse::Generics> {
136        None
137    }
138
139    fn generic_constraints(&self) -> Option<&crate::parse::GenericConstraints> {
140        None
141    }
142}