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}