auto_default/lib.rs
1#, "?style=flat-square&logo=rust)](https://crates.io/crates/", env!("CARGO_PKG_NAME"), ")")]
2#, "?style=flat-square&logo=docs.rs)](https://docs.rs/", env!("CARGO_PKG_NAME"), ")")]
3#"]
4//! 
5//! [](https://github.com/nik-rev/auto-default)
6//!
7//! This crate provides an attribute macro `#[auto_default]`, which adds a default field value of
8//! `Default::default()` to fields that do not have one.
9//!
10//! ```toml
11#![doc = concat!(env!("CARGO_PKG_NAME"), " = ", "\"", env!("CARGO_PKG_VERSION_MAJOR"), ".", env!("CARGO_PKG_VERSION_MINOR"), "\"")]
12//! ```
13//!
14//! Note: `auto-default` has *zero* dependencies. Not even `syn`! The compile times are very fast.
15//!
16//! # Showcase
17//!
18//! Rust's [default field values](https://github.com/rust-lang/rust/issues/132162) allow
19//! the shorthand `Struct { field, .. }` instead of the lengthy `Struct { field, ..Default::default() }`
20//!
21//! For `..` instead of `..Default::default()` to work,
22//! your `Struct` needs **all** fields to have a default value.
23//!
24//! This often means `= Default::default()` boilerplate on every field, because it is
25//! very common to want field defaults to be the value of their `Default` implementation
26//!
27//! ## Before
28//!
29//! ```rust
30//! # #![feature(default_field_values)]
31//! # #![feature(const_trait_impl)]
32//! # #![feature(const_default)]
33//! # #![feature(derive_const)]
34//! # use auto_default::auto_default;
35//! # #[derive_const(Default)]
36//! # struct Rect { value: f32 }
37//! # #[derive_const(Default)]
38//! # struct Size { value: f32 }
39//! # #[derive_const(Default)]
40//! # struct Point { value: f32 }
41//! #[derive(Default)]
42//! pub struct Layout {
43//! order: u32 = Default::default(),
44//! location: Point = Default::default(),
45//! size: Size = Default::default(),
46//! content_size: Size = Default::default(),
47//! scrollbar_size: Size = Default::default(),
48//! border: Rect = Default::default(),
49//! padding: Rect = Default::default(),
50//! margin: Rect = Default::default(),
51//! }
52//! ```
53//!
54//! ## With `#[auto_default]`
55//!
56//! ```rust
57//! # #![feature(default_field_values)]
58//! # #![feature(const_trait_impl)]
59//! # #![feature(const_default)]
60//! # #![feature(derive_const)]
61//! # use auto_default::auto_default;
62//! # #[derive_const(Default)]
63//! # struct Rect { value: f32 }
64//! # #[derive_const(Default)]
65//! # struct Size { value: f32 }
66//! # #[derive_const(Default)]
67//! # struct Point { value: f32 }
68//! #[auto_default]
69//! #[derive(Default)]
70//! pub struct Layout {
71//! order: u32,
72//! location: Point,
73//! size: Size,
74//! content_size: Size,
75//! scrollbar_size: Size,
76//! border: Rect,
77//! padding: Rect,
78//! margin: Rect,
79//! }
80//! ```
81//!
82//! You can apply the [`#[auto_default]`](macro@auto_default) macro to `struct`s with named fields, and `enum`s.
83//!
84//! If any field or variant has the `#[auto_default(skip)]` attribute, a default field value of `Default::default()`
85//! will **not** be added
86//!
87//! # Global Import
88//!
89//! This will make `#[auto_default]` globally accessible in your entire crate, without needing to import it:
90//!
91//! ```
92//! #[macro_use(auto_default)]
93//! extern crate auto_default;
94//! ```
95use std::iter::Peekable;
96
97use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
98
99/// Adds a default field value of `Default::default()` to fields that don't have one
100///
101/// # Example
102///
103/// Turns this:
104///
105/// ```rust
106/// # #![feature(default_field_values)]
107/// # #![feature(const_trait_impl)]
108/// # #![feature(const_default)]
109/// #[auto_default]
110/// struct User {
111/// age: u8,
112/// is_admin: bool = false
113/// }
114/// # use auto_default::auto_default;
115/// ```
116///
117/// Into this:
118///
119/// ```rust
120/// # #![feature(default_field_values)]
121/// # #![feature(const_trait_impl)]
122/// # #![feature(const_default)]
123/// struct User {
124/// age: u8 = Default::default(),
125/// is_admin: bool = false
126/// }
127/// ```
128///
129/// This macro applies to `struct`s with named fields, and enums.
130///
131/// # Do not add `= Default::default()` field value to select fields
132///
133/// If you do not want a specific field to have a default, you can opt-out
134/// with `#[auto_default(skip)]`:
135///
136/// ```rust
137/// # #![feature(default_field_values)]
138/// # #![feature(const_trait_impl)]
139/// # #![feature(const_default)]
140/// #[auto_default]
141/// struct User {
142/// #[auto_default(skip)]
143/// age: u8,
144/// is_admin: bool
145/// }
146/// # use auto_default::auto_default;
147/// ```
148///
149/// The above is transformed into this:
150///
151/// ```rust
152/// # #![feature(default_field_values)]
153/// # #![feature(const_trait_impl)]
154/// # #![feature(const_default)]
155/// struct User {
156/// age: u8,
157/// is_admin: bool = Default::default()
158/// }
159/// ```
160#[proc_macro_attribute]
161pub fn auto_default(args: TokenStream, input: TokenStream) -> TokenStream {
162 let mut compile_errors = TokenStream::new();
163
164 if !args.is_empty() {
165 compile_errors.extend(create_compile_error!(
166 args.into_iter().next(),
167 "no arguments expected",
168 ));
169 }
170
171 // Input supplied by the user. All tokens from here will
172 // get sent back to `output`
173 let mut source = input.into_iter().peekable();
174
175 // We collect all tokens into here and then return this
176 let mut sink = TokenStream::new();
177
178 // #[derive(Foo)]
179 // pub(in crate) struct Foo
180 stream_attrs(
181 &mut source,
182 &mut sink,
183 &mut compile_errors,
184 // no skip allowed on the container, would make no sense
185 // (just don't use the `#[auto_default]` at all at that point!)
186 IsSkipAllowed(false),
187 );
188
189 // pub(in crate) struct Foo
190 // ^^^^^^^^^^^^^
191 stream_vis(&mut source, &mut sink);
192
193 // pub(in crate) struct Foo
194 // ^^^^^^
195 let item_kind = match source.next() {
196 Some(TokenTree::Ident(kw)) if kw.to_string() == "struct" => {
197 sink.extend([kw]);
198 ItemKind::Struct
199 }
200 Some(TokenTree::Ident(kw)) if kw.to_string() == "enum" => {
201 sink.extend([kw]);
202 ItemKind::Enum
203 }
204 tt => {
205 compile_errors.extend(create_compile_error!(
206 tt,
207 "expected a `struct` or an `enum`"
208 ));
209 return compile_errors;
210 }
211 };
212
213 // struct Foo
214 // ^^^
215 let item_ident_span = stream_ident(&mut source, &mut sink)
216 .expect("`struct` or `enum` keyword is always followed by an identifier");
217
218 // Generics
219 //
220 // struct Foo<Bar, Baz: Trait> where Baz: Quux { ... }
221 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
222 let source_item_fields = loop {
223 match source.next() {
224 // Fields of the struct
225 Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => break group,
226 // This token is part of the generics of the struct
227 Some(tt) => sink.extend([tt]),
228 // reached end of input
229 None => {
230 // note: if enum, this is unreachable because `enum Foo` is invalid (requires `{}`),
231 // whilst `struct Foo;` is completely valid
232 compile_errors.extend(CompileError::new(
233 item_ident_span,
234 "expected struct with named fields",
235 ));
236 return compile_errors;
237 }
238 }
239 };
240
241 match item_kind {
242 ItemKind::Struct => {
243 sink.extend([add_default_field_values(
244 source_item_fields,
245 &mut compile_errors,
246 // none of the fields are considered to be skipped initially
247 IsSkip(false),
248 )]);
249 }
250 ItemKind::Enum => {
251 let mut source_variants = source_item_fields.stream().into_iter().peekable();
252 let mut sink_variants = TokenStream::new();
253
254 loop {
255 // if this variant is marked #[auto_default(skip)]
256 let is_skip = stream_attrs(
257 &mut source_variants,
258 &mut sink_variants,
259 &mut compile_errors,
260 // can skip the variant, which removes auto-default for all
261 // fields
262 IsSkipAllowed(true),
263 );
264
265 // variants technically can have visibility, at least on a syntactic level
266 //
267 // pub Variant { }
268 // ^^^
269 stream_vis(&mut source_variants, &mut sink_variants);
270
271 // Variant { }
272 // ^^^^^^^
273 let Some(variant_ident_span) =
274 stream_ident(&mut source_variants, &mut sink_variants)
275 else {
276 // that means we have an enum with no variants, e.g.:
277 //
278 // enum Never {}
279 //
280 // When we parse the variants, there won't be an identifier
281 break;
282 };
283
284 // only variants with named fields can be marked `#[auto_default(skip)]`
285 let mut disallow_skip = || {
286 if is_skip.0 {
287 compile_errors.extend(CompileError::new(
288 variant_ident_span,
289 concat!(
290 "`#[auto_default(skip)]` is",
291 " only allowed on variants with named fields"
292 ),
293 ));
294 }
295 };
296
297 match source_variants.peek() {
298 // Enum variant with named fields. Add default field values.
299 Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => {
300 let Some(TokenTree::Group(named_variant_fields)) = source_variants.next()
301 else {
302 unreachable!()
303 };
304 sink_variants.extend([add_default_field_values(
305 named_variant_fields,
306 &mut compile_errors,
307 is_skip,
308 )]);
309
310 stream_enum_variant_discriminant_and_comma(
311 &mut source_variants,
312 &mut sink_variants,
313 );
314 }
315 // Enum variant with unnamed fields.
316 Some(TokenTree::Group(group))
317 if group.delimiter() == Delimiter::Parenthesis =>
318 {
319 disallow_skip();
320 let Some(TokenTree::Group(unnamed_variant_fields)) = source_variants.next()
321 else {
322 unreachable!()
323 };
324 sink_variants.extend([unnamed_variant_fields]);
325
326 stream_enum_variant_discriminant_and_comma(
327 &mut source_variants,
328 &mut sink_variants,
329 );
330 }
331 // This was a unit variant. Next variant may exist,
332 // if it does it is parsed on next iteration
333 Some(TokenTree::Punct(punct))
334 if punct.as_char() == ',' || punct.as_char() == '=' =>
335 {
336 disallow_skip();
337 stream_enum_variant_discriminant_and_comma(
338 &mut source_variants,
339 &mut sink_variants,
340 );
341 }
342 // Unit variant, with no comma at the end. This is the last variant
343 None => {
344 disallow_skip();
345 break;
346 }
347 Some(_) => unreachable!(),
348 }
349 }
350
351 let mut sink_variants = Group::new(source_item_fields.delimiter(), sink_variants);
352 sink_variants.set_span(source_item_fields.span());
353 sink.extend([sink_variants]);
354 }
355 }
356
357 sink.extend(compile_errors);
358
359 sink
360}
361
362struct IsSkip(bool);
363struct IsSkipAllowed(bool);
364
365/// Streams enum variant discriminant + comma at the end from `source` into `sink`
366///
367/// enum Example {
368/// Three,
369/// ^
370/// Two(u32) = 2,
371/// ^^^^^
372/// Four { hello: u32 } = 4,
373/// ^^^^^
374/// }
375fn stream_enum_variant_discriminant_and_comma(source: &mut Source, sink: &mut Sink) {
376 match source.next() {
377 // No discriminant, there may be another variant after this
378 Some(TokenTree::Punct(punct)) if punct.as_char() == ',' => {
379 sink.extend([punct]);
380 }
381 // No discriminant, this is the final enum variant
382 None => {}
383 // Enum variant has a discriminant
384 Some(TokenTree::Punct(punct)) if punct.as_char() == '=' => {
385 sink.extend([punct]);
386
387 // Stream discriminant expression from `source` into `sink`
388 loop {
389 match source.next() {
390 // End of discriminant, there may be a variant after this
391 Some(TokenTree::Punct(punct)) if punct.as_char() == ',' => {
392 sink.extend([punct]);
393 break;
394 }
395 // This token is part of the variant's expression
396 Some(tt) => {
397 sink.extend([tt]);
398 }
399 // End of discriminant, this is the last variant
400 None => break,
401 }
402 }
403 }
404 Some(_) => unreachable!(),
405 }
406}
407
408type Source = Peekable<proc_macro::token_stream::IntoIter>;
409type Sink = TokenStream;
410
411/// Streams the identifier from `input` into `output`, returning its span, if the identifier exists
412fn stream_ident(source: &mut Source, sink: &mut Sink) -> Option<Span> {
413 let ident = source.next()?;
414 let span = ident.span();
415 sink.extend([ident]);
416 Some(span)
417}
418
419// Parses attributes
420//
421// #[attr] #[attr] pub field: Type
422// #[attr] #[attr] struct Foo
423// #[attr] #[attr] enum Foo
424//
425// Returns `true` if `#[auto_default(skip)]` was encountered
426fn stream_attrs(
427 source: &mut Source,
428 sink: &mut Sink,
429 errors: &mut TokenStream,
430 is_skip_allowed: IsSkipAllowed,
431) -> IsSkip {
432 let mut is_skip = None;
433
434 let is_skip = loop {
435 if !matches!(source.peek(), Some(TokenTree::Punct(hash)) if *hash == '#') {
436 break is_skip;
437 };
438
439 // #[some_attr]
440 // ^
441 let pound = source.next();
442
443 // #[some_attr]
444 // ^^^^^^^^^^^
445 let Some(TokenTree::Group(attr)) = source.next() else {
446 unreachable!()
447 };
448
449 // #[some_attr = hello]
450 // ^^^^^^^^^^^^^^^^^
451 let mut attr_tokens = attr.stream().into_iter().peekable();
452
453 // Check if this attribute is `#[auto_default(skip)]`
454 if let Some(skip_span) = is_skip_attribute(&mut attr_tokens, errors) {
455 if is_skip.is_some() {
456 // Disallow 2 attributes on a single field:
457 //
458 // #[auto_default(skip)]
459 // #[auto_default(skip)]
460 errors.extend(CompileError::new(
461 skip_span,
462 "duplicate `#[auto_default(skip)]`",
463 ));
464 } else {
465 is_skip = Some(skip_span);
466 }
467 continue;
468 }
469
470 // #[attr]
471 // ^
472 sink.extend(pound);
473
474 // Re-construct the `[..]` for the attribute
475 //
476 // #[attr]
477 // ^^^^^^
478 let mut group = Group::new(attr.delimiter(), attr_tokens.collect());
479 group.set_span(attr.span());
480
481 // #[attr]
482 // ^^^^^^
483 sink.extend([group]);
484 };
485
486 if let Some(skip_span) = is_skip
487 && !is_skip_allowed.0
488 {
489 errors.extend(CompileError::new(
490 skip_span,
491 "`#[auto_default(skip)]` is not allowed on container",
492 ));
493 }
494
495 IsSkip(is_skip.is_some())
496}
497
498/// if `source` is exactly `auto_default(skip)`, returns `Some(span)`
499/// with `span` being the `Span` of the `skip` identifier
500fn is_skip_attribute(source: &mut Source, errors: &mut TokenStream) -> Option<Span> {
501 let Some(TokenTree::Ident(ident)) = source.peek() else {
502 return None;
503 };
504
505 if ident.to_string() != "auto_default" {
506 return None;
507 };
508
509 // #[auto_default(skip)]
510 // ^^^^^^^^^^^^
511 let ident = source.next().unwrap();
512
513 // We know it is `#[auto_default ???]`, we need to validate that `???`
514 // is exactly `(skip)` now
515
516 // #[auto_default(skip)]
517 // ^^^^^^^^^^^^
518 let auto_default_span = ident.span();
519
520 // #[auto_default(skip)]
521 // ^^^^^^
522 let group = match source.next() {
523 Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Parenthesis => group,
524 Some(tt) => {
525 errors.extend(CompileError::new(tt.span(), "expected `(skip)`"));
526 return None;
527 }
528 None => {
529 errors.extend(CompileError::new(
530 auto_default_span,
531 "expected `(skip)` after this",
532 ));
533 return None;
534 }
535 };
536
537 // #[auto_default(skip)]
538 // ^^^^
539 let mut inside = group.stream().into_iter();
540
541 // #[auto_default(skip)]
542 // ^^^^
543 let ident_skip = match inside.next() {
544 Some(TokenTree::Ident(ident)) => ident,
545 Some(tt) => {
546 errors.extend(CompileError::new(tt.span(), "expected `skip`"));
547 return None;
548 }
549 None => {
550 errors.extend(CompileError::new(
551 group.span(),
552 "expected `(skip)`, found `()`",
553 ));
554 return None;
555 }
556 };
557
558 if ident_skip.to_string() != "skip" {
559 errors.extend(CompileError::new(ident_skip.span(), "expected `skip`"));
560 return None;
561 }
562
563 // Validate that there's nothing after `skip`
564 //
565 // #[auto_default(skip )]
566 // ^^^^
567 if let Some(tt) = inside.next() {
568 errors.extend(CompileError::new(tt.span(), "unexpected token"));
569 return None;
570 }
571
572 Some(ident_skip.span())
573}
574
575fn stream_vis(source: &mut Source, sink: &mut Sink) {
576 // Remove visibility if it is present
577 //
578 // pub(in crate) struct
579 // ^^^^^^^^^^^^^
580 if let Some(TokenTree::Ident(vis)) = source.peek()
581 && vis.to_string() == "pub"
582 {
583 // pub(in crate) struct
584 // ^^^
585 sink.extend(source.next());
586
587 if let Some(TokenTree::Group(group)) = source.peek()
588 && let Delimiter::Parenthesis = group.delimiter()
589 {
590 // pub(in crate) struct
591 // ^^^^^^^^^^
592 sink.extend(source.next());
593 }
594 };
595}
596
597#[derive(PartialEq)]
598enum ItemKind {
599 Struct,
600 Enum,
601}
602
603/// `fields` is [`StructFields`] in the grammar.
604///
605/// It is the curly braces, and everything within, for a struct with named fields,
606/// or an enum variant with named fields.
607///
608/// These fields are transformed by adding `= Default::default()` to every
609/// field that doesn't already have a default value.
610///
611/// If a field is marked with `#[auto_default(skip)]`, no default value will be
612/// added
613///
614/// [`StructFields`]: https://doc.rust-lang.org/reference/items/structs.html#grammar-StructFields
615fn add_default_field_values(
616 fields: Group,
617 compile_errors: &mut TokenStream,
618 is_skip_variant: IsSkip,
619) -> Group {
620 // All the tokens corresponding to the struct's field, passed by the user
621 // These tokens will eventually all be sent to `output_fields`,
622 // plus a few extra for any `Default::default()` that we output
623 let mut input_fields = fields.stream().into_iter().peekable();
624
625 // The tokens corresponding to the fields of the output struct
626 let mut output_fields = TokenStream::new();
627
628 // Parses all fields.
629 // Each iteration parses a single field
630 'parse_field: loop {
631 // #[serde(rename = "x")] pub field: Type
632 // ^^^^^^^^^^^^^^^^^^^^^^
633 let is_skip_field = stream_attrs(
634 &mut input_fields,
635 &mut output_fields,
636 compile_errors,
637 IsSkipAllowed(true),
638 );
639 let is_skip = is_skip_field.0 || is_skip_variant.0;
640
641 // pub field: Type
642 // ^^^
643 stream_vis(&mut input_fields, &mut output_fields);
644
645 // pub field: Type
646 // ^^^^^
647 let Some(field_ident_span) = stream_ident(&mut input_fields, &mut output_fields) else {
648 // No fields. e.g.: `struct Struct {}`
649 break;
650 };
651
652 // field: Type
653 // ^
654 output_fields.extend(input_fields.next());
655
656 // Everything after the `:` in the field
657 //
658 // Involves:
659 //
660 // - Adding default value of `= Default::default()` if one is not present
661 // - Continue to next iteration of the loop
662 loop {
663 match input_fields.peek() {
664 // This field has a custom default field value
665 //
666 // field: Type = default
667 // ^
668 Some(TokenTree::Punct(p)) if p.as_char() == '=' => {
669 if is_skip {
670 compile_errors.extend(CompileError::new(
671 field_ident_span,
672 concat!(
673 "this field is marked `#[auto_default(skip)]`,",
674 " which does nothing since this field has a",
675 " default value: `= ...`\n",
676 "the attribute `#[auto_default(skip)]` can be removed"
677 ),
678 ));
679 }
680
681 loop {
682 match input_fields.next() {
683 Some(TokenTree::Punct(p)) if p == ',' => {
684 output_fields.extend([p]);
685 // Comma after field. Field is finished.
686 continue 'parse_field;
687 }
688 Some(tt) => output_fields.extend([tt]),
689 // End of input. Field is finished. This is the last field
690 None => break 'parse_field,
691 }
692 }
693 }
694 // Reached end of field, has comma at the end, no custom default value
695 //
696 // field: Type,
697 // ^
698 //
699 // OR, this comma is part of the field's type:
700 //
701 // field: HashMap<u8, u8>,
702 // ^
703 Some(TokenTree::Punct(p)) if p.as_char() == ',' => {
704 let comma = input_fields.next().expect("match on `Some`");
705
706 /// What does this comma represent?
707 #[derive(Debug)]
708 enum CommaStatus {
709 /// End of field
710 EndOfField0,
711 /// End of field, with 2 tokens to insert after end of the field
712 EndOfField1(TokenTree),
713 /// Part of type
714 PartOfType0,
715 /// Part of type, with 1 token to insert after the comma
716 PartOfType1(TokenTree),
717 }
718
719 // When we encounter a COMMA token while parsing
720 let comma_status = match input_fields.peek() {
721 // pub field: Type
722 // ^^^
723 Some(TokenTree::Ident(ident)) if ident.to_string() == "pub" => {
724 // this `comma` is end of the field
725 //
726 // field: HashMap<u8, u8>,
727 // ^ `comma`
728 // pub next_field: Type
729 // ^^^ `ident`
730 CommaStatus::EndOfField0
731 }
732
733 // #[foo(bar)] pub field: Type
734 // ^
735 Some(TokenTree::Punct(punct)) if *punct == '#' => {
736 // this `comma` is end of the field
737 //
738 // field: HashMap<u8, u8>,
739 // ^ this
740 // #[foo(bar)] next_field: HashMap<u8, u8>,
741 CommaStatus::EndOfField0
742 }
743
744 // field: Type
745 // ^^^^^
746 Some(TokenTree::Ident(_)) => {
747 let field_or_ty_ident = input_fields.next().expect("match on `Some`");
748
749 match input_fields.peek() {
750 // field: Type
751 // ^
752 Some(TokenTree::Punct(punct)) if *punct == ':' => {
753 let field_ident = field_or_ty_ident;
754
755 CommaStatus::EndOfField1(field_ident)
756 }
757 // This identifier is part of the type
758 //
759 // field: HashMap<u8, u8>,
760 // ^^
761 _ => {
762 let ty_ident = field_or_ty_ident;
763 CommaStatus::PartOfType1(ty_ident)
764 }
765 }
766 }
767
768 // This comma is part of a type, NOT end of field!
769 //
770 // pub field: HashMap<String, String>
771 // ^
772 Some(_) => CommaStatus::PartOfType0,
773
774 // Reached end of input. This comma is end of the field
775 //
776 // field: Type,
777 // ^
778 None => CommaStatus::EndOfField0,
779 };
780
781 let insert_extra_token = match comma_status {
782 CommaStatus::EndOfField0 => None,
783 CommaStatus::EndOfField1(token_tree) => Some(token_tree),
784 CommaStatus::PartOfType0 => {
785 output_fields.extend([comma]);
786 continue;
787 }
788 CommaStatus::PartOfType1(token_tree) => {
789 output_fields.extend([comma]);
790 output_fields.extend([token_tree]);
791 continue;
792 }
793 };
794
795 // Now that we're here, we can be 100% sure that the `comma` we have
796 // is at the END of the field
797
798 // Insert default value before the comma
799 //
800 // field: Type = Default::default(),
801 // ^^^^^^^^^^^^^^^^^^^^
802 if !is_skip {
803 output_fields.extend(default(field_ident_span));
804 }
805
806 // field: Type = Default::default(),
807 // ^
808 output_fields.extend([comma]);
809
810 if let Some(token_tree) = insert_extra_token {
811 // Insert the extra token which we needed to take when figuring out if this
812 // comma is part of the type, or end of the field
813
814 output_fields.extend([token_tree]);
815 }
816
817 // Next iteration handles the next field
818 continue 'parse_field;
819 }
820 // This token is part of the field's type
821 //
822 // field: some::Type
823 // ^^^^
824 Some(_) => output_fields.extend(input_fields.next()),
825 // Reached end of input, and it has no comma.
826 // This is the last field.
827 //
828 // struct Foo {
829 // field: Type
830 // ^
831 // }
832 None => {
833 if !is_skip {
834 output_fields.extend(default(field_ident_span));
835 }
836 // No more fields
837 break 'parse_field;
838 }
839 }
840 }
841 }
842 let mut g = Group::new(Delimiter::Brace, output_fields);
843 g.set_span(fields.span());
844 g
845}
846
847// = ::core::default::Default::default()
848fn default(span: Span) -> [TokenTree; 14] {
849 [
850 TokenTree::Punct(Punct::new('=', Spacing::Alone)),
851 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
852 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
853 TokenTree::Ident(Ident::new("core", span)),
854 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
855 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
856 TokenTree::Ident(Ident::new("default", span)),
857 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
858 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
859 TokenTree::Ident(Ident::new("Default", span)),
860 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
861 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(span),
862 TokenTree::Ident(Ident::new("default", span)),
863 TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())).with_span(span),
864 ]
865}
866
867macro_rules! create_compile_error {
868 ($spanned:expr, $($tt:tt)*) => {{
869 let span = if let Some(spanned) = $spanned {
870 spanned.span()
871 } else {
872 Span::call_site()
873 };
874 CompileError::new(span, format!($($tt)*))
875 }};
876}
877use create_compile_error;
878
879/// `.into_iter()` generates `compile_error!($message)` at `$span`
880struct CompileError {
881 /// Where the compile error is generates
882 pub span: Span,
883 /// Message of the compile error
884 pub message: String,
885}
886
887impl CompileError {
888 /// Create a new compile error
889 pub fn new(span: Span, message: impl AsRef<str>) -> Self {
890 Self {
891 span,
892 message: message.as_ref().to_string(),
893 }
894 }
895}
896
897impl IntoIterator for CompileError {
898 type Item = TokenTree;
899 type IntoIter = std::array::IntoIter<Self::Item, 8>;
900
901 fn into_iter(self) -> Self::IntoIter {
902 [
903 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(self.span),
904 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(self.span),
905 TokenTree::Ident(Ident::new("core", self.span)),
906 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(self.span),
907 TokenTree::Punct(Punct::new(':', Spacing::Joint)).with_span(self.span),
908 TokenTree::Ident(Ident::new("compile_error", self.span)),
909 TokenTree::Punct(Punct::new('!', Spacing::Alone)).with_span(self.span),
910 TokenTree::Group(Group::new(Delimiter::Brace, {
911 TokenStream::from(
912 TokenTree::Literal(Literal::string(&self.message)).with_span(self.span),
913 )
914 }))
915 .with_span(self.span),
916 ]
917 .into_iter()
918 }
919}
920
921trait TokenTreeExt {
922 /// Set span of `TokenTree` without needing to create a new binding
923 fn with_span(self, span: Span) -> TokenTree;
924}
925
926impl TokenTreeExt for TokenTree {
927 fn with_span(mut self, span: Span) -> TokenTree {
928 self.set_span(span);
929 self
930 }
931}