Skip to main content

virtue_next/generate/
gen_struct.rs

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