Skip to main content

virtue_next/generate/
gen_struct.rs

1use super::{
2    AttributeContainer, Field, FieldBuilder, Impl, ImplFor, Parent, Path, StreamBuilder,
3    StringOrIdent,
4};
5use crate::Result;
6use crate::parse::{Generic, Generics, Visibility};
7use crate::prelude::{Delimiter, Ident, Span, TokenStream};
8
9/// Builder to generate a struct.
10/// Defaults to a struct with named fields `struct <Name> { <field>: <ty>, ... }`
11pub struct GenStruct<'a, P: Parent> {
12    parent: &'a mut P,
13    name: Ident,
14    visibility: Visibility,
15    generics: Option<Generics>,
16    fields: Vec<Field>,
17    derives: Vec<Path>,
18    attributes: Vec<StreamBuilder>,
19    additional: Vec<StreamBuilder>,
20    struct_type: StructType,
21}
22
23impl<'a, P: Parent> GenStruct<'a, P> {
24    pub(crate) fn new(parent: &'a mut P, name: impl Into<String>) -> Self {
25        Self {
26            parent,
27            name: Ident::new(name.into().as_str(), Span::call_site()),
28            visibility: Visibility::Default,
29            generics: None,
30            fields: Vec::new(),
31            derives: Vec::new(),
32            attributes: Vec::new(),
33            additional: Vec::new(),
34            struct_type: StructType::Named,
35        }
36    }
37
38    /// Make the struct a zero-sized type (no fields)
39    ///
40    /// Any fields will be ignored
41    ///
42    /// ```
43    /// # use virtue::prelude::Generator;
44    /// # let mut generator = Generator::with_name("Fooz");
45    /// generator
46    ///     .generate_struct("Foo")
47    ///     .make_zst()
48    ///     .add_field("bar", "u16")
49    ///     .add_field("baz", "String");
50    /// # generator.assert_eq("struct Foo ;");
51    /// # Ok::<_, virtue::Error>(())
52    /// ```
53    ///
54    /// Generates:
55    /// ```
56    /// struct Foo;
57    /// ```
58    pub fn make_zst(&mut self) -> &mut Self {
59        self.struct_type = StructType::Zst;
60        self
61    }
62
63    /// Make the struct fields unnamed
64    ///
65    /// The names of any field will be ignored
66    ///
67    /// ```
68    /// # use virtue::prelude::Generator;
69    /// # let mut generator = Generator::with_name("Fooz");
70    /// generator
71    ///     .generate_struct("Foo")
72    ///     .make_tuple()
73    ///     .add_field("bar", "u16")
74    ///     .add_field("baz", "String");
75    /// # generator.assert_eq("struct Foo (u16 , String ,) ;");
76    /// # Ok::<_, virtue::Error>(())
77    /// ```
78    ///
79    /// Generates:
80    /// ```
81    /// struct Foo(u16, String);
82    /// ```
83    pub fn make_tuple(&mut self) -> &mut Self {
84        self.struct_type = StructType::Unnamed;
85        self
86    }
87
88    /// Make the struct `pub`. By default the struct will have no visibility modifier and will only be visible in the current scope.
89    pub fn make_pub(&mut self) -> &mut Self {
90        self.visibility = Visibility::Pub;
91        self
92    }
93
94    /// Inherit the generic parameters of the parent type.
95    ///
96    /// ```
97    /// # use virtue::prelude::Generator;
98    /// # let mut generator = Generator::with_name("Bar").with_lifetime("a");
99    /// // given a derive on struct Bar<'a>
100    /// generator
101    ///     .generate_struct("Foo")
102    ///     .inherit_generics()
103    ///     .add_field("bar", "&'a str");
104    /// # generator.assert_eq("struct Foo < 'a > { bar : &'a str , }");
105    /// # Ok::<_, virtue::Error>(())
106    /// ```
107    ///
108    /// Generates:
109    /// ```ignore
110    /// // given a derive on struct Bar<'a>
111    /// struct Foo<'a> {
112    ///     bar: &'a str
113    /// }
114    /// ```
115    pub fn inherit_generics(&mut self) -> &mut Self {
116        self.generics = self.parent.generics().cloned();
117        self
118    }
119
120    /// Append generic parameters to the type.
121    ///
122    /// ```
123    /// # use virtue::prelude::Generator;
124    /// # use virtue::parse::{Generic, Lifetime};
125    /// # use proc_macro2::{Ident, Span};
126    /// # let mut generator = Generator::with_name("Bar").with_lifetime("a");
127    /// generator
128    ///     .generate_struct("Foo")
129    ///     .with_generics([Lifetime { ident: Ident::new("a", Span::call_site()), constraint: vec![] }.into()])
130    ///     .add_field("bar", "&'a str");
131    /// # generator.assert_eq("struct Foo < 'a > { bar : &'a str , }");
132    /// # Ok::<_, virtue::Error>(())
133    /// ```
134    ///
135    /// Generates:
136    /// ```ignore
137    /// struct Foo<'a> {
138    ///     bar: &'a str
139    /// }
140    /// ```
141    pub fn with_generics(&mut self, generics: impl IntoIterator<Item = Generic>) -> &mut Self {
142        self.generics
143            .get_or_insert_with(|| Generics(Vec::new()))
144            .extend(generics);
145        self
146    }
147
148    /// Add a generic parameter to the type.
149    ///
150    /// ```
151    /// # use virtue::prelude::Generator;
152    /// # use virtue::parse::{Generic, Lifetime};
153    /// # use proc_macro2::{Ident, Span};
154    /// # let mut generator = Generator::with_name("Bar").with_lifetime("a");
155    /// generator
156    ///     .generate_struct("Foo")
157    ///     .with_generic(Lifetime { ident: Ident::new("a", Span::call_site()), constraint: vec![] }.into())
158    ///     .add_field("bar", "&'a str");
159    /// # generator.assert_eq("struct Foo < 'a > { bar : &'a str , }");
160    /// # Ok::<_, virtue::Error>(())
161    /// ```
162    ///
163    /// Generates:
164    /// ```ignore
165    /// struct Foo<'a> {
166    ///     bar: &'a str
167    /// }
168    /// ```
169    pub fn with_generic(&mut self, generic: Generic) -> &mut Self {
170        self.generics
171            .get_or_insert_with(|| Generics(Vec::new()))
172            .push(generic);
173        self
174    }
175
176    /// Add a derive macro to the struct.
177    ///
178    /// ```
179    /// # use virtue::prelude::Generator;
180    /// # use virtue::generate::Path;
181    /// # let mut generator = Generator::with_name("Bar");
182    /// generator
183    ///     .generate_struct("Foo")
184    ///     .with_derive("Clone")
185    ///     .with_derive("Default")
186    ///     .with_derive(Path::from_iter(vec!["serde", "Deserialize"]));
187    /// # generator.assert_eq("# [derive (Clone , Default , serde ::Deserialize)] struct Foo { }");
188    /// # Ok::<_, virtue::Error>(())
189    /// ```
190    ///
191    /// Generates:
192    /// ```ignore
193    /// #[derive(Clone, Default, serde::Deserialize)]
194    /// struct Foo { }
195    /// ```
196    pub fn with_derive(&mut self, derive: impl Into<Path>) -> &mut Self {
197        AttributeContainer::with_derive(self, derive)
198    }
199
200    /// Add derive macros to the struct.
201    ///
202    /// ```
203    /// # use virtue::prelude::Generator;
204    /// # use virtue::generate::Path;
205    /// # let mut generator = Generator::with_name("Bar");
206    /// generator
207    ///     .generate_struct("Foo")
208    ///     .with_derives([
209    ///         "Clone".into(),
210    ///         "Default".into(),
211    ///         Path::from_iter(vec!["serde", "Deserialize"]),
212    ///     ]);
213    /// # generator.assert_eq("# [derive (Clone , Default , serde ::Deserialize)] struct Foo { }");
214    /// # Ok::<_, virtue::Error>(())
215    /// ```
216    ///
217    /// Generates:
218    /// ```ignore
219    /// #[derive(Clone, Default, serde::Deserialize)]
220    /// struct Foo { }
221    /// ```
222    pub fn with_derives<T: Into<Path>>(
223        &mut self,
224        derives: impl IntoIterator<Item = T>,
225    ) -> &mut Self {
226        AttributeContainer::with_derives(self, derives)
227    }
228
229    /// Add an attribute to the struct. For `#[derive(...)]`, use [`with_derive`](Self::with_derive)
230    /// instead.
231    ///
232    /// ```
233    /// # use virtue::prelude::Generator;
234    /// # let mut generator = Generator::with_name("Bar");
235    /// generator
236    ///     .generate_struct("Foo")
237    ///     .with_attribute("serde", |b| {
238    ///         b.push_parsed("(rename_all = \"camelCase\")")?;
239    ///         Ok(())
240    ///     })?;
241    /// # generator.assert_eq("# [serde (rename_all = \"camelCase\")] struct Foo { }");
242    /// # Ok::<_, virtue::Error>(())
243    /// ```
244    ///
245    /// Generates:
246    /// ```ignore
247    /// #[serde(rename_all = "camelCase")]
248    /// struct Foo { }
249    /// ```
250    pub fn with_attribute(
251        &mut self,
252        name: impl AsRef<str>,
253        value: impl FnOnce(&mut StreamBuilder) -> Result,
254    ) -> Result<&mut Self> {
255        AttributeContainer::with_attribute(self, name, value)
256    }
257
258    /// Add a parsed attribute to the struct. For `#[derive(...)]`, use [`with_derive`](Self::with_derive)
259    /// instead.
260    ///
261    /// ```
262    /// # use virtue::prelude::Generator;
263    /// # let mut generator = Generator::with_name("Bar");
264    /// generator
265    ///     .generate_struct("Foo")
266    ///     .with_parsed_attribute("serde(rename_all = \"camelCase\")")?;
267    /// # generator.assert_eq("# [serde (rename_all = \"camelCase\")] struct Foo { }");
268    /// # Ok::<_, virtue::Error>(())
269    /// ```
270    ///
271    /// Generates:
272    /// ```ignore
273    /// #[serde(rename_all = "camelCase")]
274    /// struct Foo { }
275    /// ```
276    pub fn with_parsed_attribute(&mut self, attribute: impl AsRef<str>) -> Result<&mut Self> {
277        AttributeContainer::with_parsed_attribute(self, attribute)
278    }
279
280    /// Add a token stream as an attribute to the struct. For `#[derive(...)]`, use
281    /// [`with_derive`](Self::with_derive) instead.
282    ///
283    /// ```
284    /// # use virtue::prelude::{Generator, TokenStream};
285    /// # use std::str::FromStr;
286    /// # let mut generator = Generator::with_name("Bar");
287    ///
288    /// let attribute = "serde(rename_all = \"camelCase\")".parse::<TokenStream>().unwrap();
289    /// generator
290    ///     .generate_struct("Foo")
291    ///     .with_attribute_stream(attribute);
292    /// # generator.assert_eq("# [serde (rename_all = \"camelCase\")] struct Foo { }");
293    /// # Ok::<_, virtue::Error>(())
294    /// ```
295    ///
296    /// Generates:
297    /// ```ignore
298    /// #[serde(rename_all = "camelCase")]
299    /// struct Foo { }
300    /// ```
301    pub fn with_attribute_stream(&mut self, attribute: impl Into<TokenStream>) -> &mut Self {
302        AttributeContainer::with_attribute_stream(self, attribute)
303    }
304
305    /// Add a field to the struct.
306    ///
307    /// Names are ignored when the Struct's fields are unnamed
308    ///
309    /// ```
310    /// # use virtue::prelude::Generator;
311    /// # let mut generator = Generator::with_name("Fooz");
312    /// generator
313    ///     .generate_struct("Foo")
314    ///     .add_field("bar", "u16")
315    ///     .add_field("baz", "String");
316    /// # generator.assert_eq("struct Foo { bar : u16 , baz : String , }");
317    /// # Ok::<_, virtue::Error>(())
318    /// ```
319    ///
320    /// Generates:
321    /// ```
322    /// struct Foo {
323    ///     bar: u16,
324    ///     baz: String,
325    /// };
326    /// ```
327    pub fn add_field(
328        &mut self,
329        name: impl Into<String>,
330        ty: impl Into<String>,
331    ) -> FieldBuilder<'_, Self> {
332        let mut fields = FieldBuilder::from(&mut self.fields);
333        fields.add_field(name, ty);
334        fields
335    }
336
337    /// Add an `impl <name> for <struct>`
338    pub fn impl_for(&mut self, name: impl Into<StringOrIdent>) -> ImplFor<'_, Self> {
339        ImplFor::new(self, name.into(), None)
340    }
341
342    /// Generate an `impl <name>` implementation. See [`Impl`] for more information.
343    pub fn r#impl(&mut self) -> Impl<'_, Self> {
344        Impl::with_parent_name(self)
345    }
346
347    /// Generate an `impl <name>` implementation. See [`Impl`] for more information.
348    ///
349    /// Alias for [`impl`] which doesn't need a `r#` prefix.
350    ///
351    /// [`impl`]: #method.impl
352    pub fn generate_impl(&mut self) -> Impl<'_, Self> {
353        Impl::with_parent_name(self)
354    }
355}
356
357impl<P: Parent> AttributeContainer for GenStruct<'_, P> {
358    fn derives(&mut self) -> &mut Vec<Path> {
359        &mut self.derives
360    }
361
362    fn attributes(&mut self) -> &mut Vec<StreamBuilder> {
363        &mut self.attributes
364    }
365}
366
367impl<'a, P: Parent> Parent for GenStruct<'a, P> {
368    fn append(&mut self, builder: StreamBuilder) {
369        self.additional.push(builder);
370    }
371
372    fn name(&self) -> &Ident {
373        &self.name
374    }
375
376    fn generics(&self) -> Option<&Generics> {
377        self.generics.as_ref()
378    }
379
380    fn generic_constraints(&self) -> Option<&crate::parse::GenericConstraints> {
381        None
382    }
383}
384
385impl<'a, P: Parent> Drop for GenStruct<'a, P> {
386    fn drop(&mut self) {
387        use std::mem::take;
388        let mut builder = StreamBuilder::new();
389
390        self.build_derives(&mut builder)
391            .build_attributes(&mut builder);
392
393        if self.visibility == Visibility::Pub {
394            builder.ident_str("pub");
395        }
396        builder.ident_str("struct").ident(self.name.clone()).append(
397            self.generics()
398                .map(Generics::impl_generics)
399                .unwrap_or_default(),
400        );
401
402        match self.struct_type {
403            StructType::Named => builder
404                .group(Delimiter::Brace, |b| {
405                    for field in self.fields.iter_mut() {
406                        field.build_attributes(b);
407                        if field.vis == Visibility::Pub {
408                            b.ident_str("pub");
409                        }
410                        b.ident_str(&field.name)
411                            .punct(':')
412                            .push_parsed(&field.ty)?
413                            .punct(',');
414                    }
415                    Ok(())
416                })
417                .expect("Could not build struct"),
418            StructType::Unnamed => builder
419                .group(Delimiter::Parenthesis, |b| {
420                    for field in self.fields.iter_mut() {
421                        field.build_attributes(b);
422                        if field.vis == Visibility::Pub {
423                            b.ident_str("pub");
424                        }
425                        b.push_parsed(&field.ty)?.punct(',');
426                    }
427                    Ok(())
428                })
429                .expect("Could not build struct")
430                .punct(';'),
431            StructType::Zst => builder.punct(';'),
432        };
433
434        for additional in take(&mut self.additional) {
435            builder.append(additional);
436        }
437        self.parent.append(builder);
438    }
439}
440
441enum StructType {
442    Named,
443    Unnamed,
444    Zst,
445}